zoukankan      html  css  js  c++  java
  • Recyclers对象池设计

    前言

    不管是netty还是sofa-jraft,使用对象池的目的就是避免重复创建对象,消耗内存,减少GC压力。

    原理

    https://www.jianshu.com/p/854b855bd198

    Recyclers在Jraft中的使用测试案例

    主要测试了在多线程模型下,能够获取和回收同一个对象。

    以及在max<0 的时候,每次都会创建一个新的不同对象。

    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package com.alipay.sofa.jraft.util;
    
    import java.util.Random;
    import java.util.concurrent.atomic.AtomicReference;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    import static org.junit.Assert.assertNotSame;
    import static org.junit.Assert.assertSame;
    import static org.junit.Assert.assertTrue;
    
    /**
     *
     * @author jiachun.fjc
     */
    public class RecyclersTest {
    
        private static Recyclers<RecyclableObject> newRecyclers(final int max) {
            return new Recyclers<RecyclableObject>(max) {
    
                @Override
                protected RecyclableObject newObject(final Recyclers.Handle handle) {
                    return new RecyclableObject(handle);
                }
            };
        }
    
        @Test(expected = IllegalStateException.class)
        public void testMultipleRecycle() {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(16);
            final RecyclableObject object = recyclers.get();
            recyclers.recycle(object, object.handle);
            recyclers.recycle(object, object.handle);
        }
    
        @Test
        public void testMultipleRecycleAtDifferentThread() throws InterruptedException {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(512);
            final RecyclableObject object = recyclers.get();
            final Thread thread1 = new Thread(() -> recyclers.recycle(object, object.handle));
            thread1.start();
            thread1.join();
            assertSame(object, recyclers.get());
        }
    
        @Test(expected = IllegalStateException.class)
        public void testRecycleMoreThanOnceAtDifferentThread() throws InterruptedException {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(1024);
            final RecyclableObject object = recyclers.get();
    
            final AtomicReference<IllegalStateException> exceptionStore = new AtomicReference<>();
            final Thread thread1 = new Thread(() -> recyclers.recycle(object, object.handle));
            thread1.start();
            thread1.join();
    
            final Thread thread2 = new Thread(() -> {
                try {
                    recyclers.recycle(object, object.handle);
                } catch (IllegalStateException e) {
                    exceptionStore.set(e);
                }
            });
            thread2.start();
            thread2.join();
            IllegalStateException exception = exceptionStore.get();
            if (exception != null) {
                throw exception;
            }
        }
    
        @Test
        public void testRecycle() {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(16);
            final RecyclableObject object = recyclers.get();
            recyclers.recycle(object, object.handle);
            final RecyclableObject object2 = recyclers.get();
            Assert.assertSame(object, object2);
            recyclers.recycle(object2, object2.handle);
        }
    
        @Test
        public void testRecycleDisable() {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(-1);
            final RecyclableObject object = recyclers.get();
            recyclers.recycle(object, object.handle);
            final RecyclableObject object2 = recyclers.get();
            assertNotSame(object, object2);
            recyclers.recycle(object2, object2.handle);
        }
    
        @Test
        public void testMaxCapacity() {
            testMaxCapacity(300);
            Random rand = new Random();
            for (int i = 0; i < 50; i++) {
                testMaxCapacity(rand.nextInt(1000) + 256); // 256 - 1256
            }
        }
    
        private static void testMaxCapacity(final int maxCapacity) {
            final Recyclers<RecyclableObject> recyclers = newRecyclers(maxCapacity);
            final RecyclableObject[] objects = new RecyclableObject[maxCapacity * 3];
            for (int i = 0; i < objects.length; i++) {
                objects[i] = recyclers.get();
            }
    
            for (int i = 0; i < objects.length; i++) {
                recyclers.recycle(objects[i], objects[i].handle);
                objects[i] = null;
            }
    
            assertTrue("The threadLocalCapacity (" + recyclers.threadLocalCapacity() + ") must be <= maxCapacity ("
                       + maxCapacity + ") as we not pool all new handles internally",
                maxCapacity >= recyclers.threadLocalCapacity());
        }
    
        static final class RecyclableObject {
    
            private final Recyclers.Handle handle;
    
            private RecyclableObject(Recyclers.Handle handle) {
                this.handle = handle;
            }
    
            public Recyclers.Handle getHandle() {
                return handle;
            }
        }
    }

    SegmentList

    *                [segment, segment, segment ...]
    * / |
    * segment segment segment
    * [0, 1 ... 127] [128, 129 ... 255] [256, 257 ... 383]

    创建一个重复利用的对象segment,内部包含一个数据,避免多次分配内存空间。

    public class SegmentList<T> {
        private static final int             SEGMENT_SHIFT = 7;
        public static final int              SEGMENT_SIZE  = 2 << (SEGMENT_SHIFT - 1);
    
        private final ArrayDeque<Segment<T>> segments;
    
        private int                          size;
    
        // Cached offset in first segment.
        private int                          firstOffset;
    
        private final boolean                recycleSegment;
        /**
         * A recyclable segment.
         * @author boyan(boyan@antfin.com)
         *
         * @param <T>
         */
        private final static class Segment<T> implements Recyclable {
            private static final  Recyclers<Segment<?>> recyclers = new Recyclers<Segment<?>>(16_382 / SEGMENT_SIZE) {
    
                                                                     @Override
                                                                     protected Segment<?> newObject(final Handle handle) {
                                                                         return new Segment<>(handle);
                                                                     }
                                                                 };
    
            public static Segment<?> newInstance(final boolean recycleSegment) {
                if (recycleSegment) {
                    return recyclers.get();
                } else {
                    return new Segment<>();
                }
            }
    
            private transient Recyclers.Handle handle;
    
            final T[]                          elements;
            int                                pos;     // end offset(exclusive)
            int                                offset;  // start offset(inclusive)
    
            Segment() {
                this(Recyclers.NOOP_HANDLE);
            }
    
            @SuppressWarnings("unchecked")
            Segment(final Recyclers.Handle handle) {
                this.elements = (T[]) new Object[SEGMENT_SIZE];
                this.pos = this.offset = 0;
                this.handle = handle;
            }
    
            void clear() {
                this.pos = this.offset = 0;
                Arrays.fill(this.elements, null);
            }
    
            @Override
            public boolean recycle() {
                clear();
                return recyclers.recycle(this, this.handle);
            }
    
            int cap() {
                return SEGMENT_SIZE - this.pos;
            }
    
            @SuppressWarnings("SuspiciousSystemArraycopy")
            private void addAll(final Object[] src, final int srcPos, final int len) {
                System.arraycopy(src, srcPos, this.elements, this.pos, len);
                this.pos += len;
            }
    
            boolean isReachEnd() {
                return this.pos == SEGMENT_SIZE;
            }
    
            boolean isEmpty() {
                return this.size() == 0;
            }
    
            void add(final T e) {
                this.elements[this.pos++] = e;
            }
    
            T get(final int index) {
                if (index >= this.pos || index < this.offset) {
                    throw new IndexOutOfBoundsException("Index=" + index + ", Offset=" + this.offset + ", Pos=" + this.pos);
                }
                return this.elements[index];
            }
    
            T peekLast() {
                return this.elements[this.pos - 1];
            }
    
            int size() {
                return this.pos - this.offset;
            }
    
            T peekFirst() {
                return this.elements[this.offset];
            }
    
            int removeFromLastWhen(final Predicate<T> predicate) {
                int removed = 0;
                for (int i = this.pos - 1; i >= this.offset; i--) {
                    T e = this.elements[i];
                    if (predicate.test(e)) {
                        this.elements[i] = null;
                        removed++;
                    } else {
                        break;
                    }
                }
                this.pos -= removed;
                return removed;
            }
    
            int removeFromFirstWhen(final Predicate<T> predicate) {
                int removed = 0;
                for (int i = this.offset; i < this.pos; i++) {
                    T e = this.elements[i];
                    if (predicate.test(e)) {
                        this.elements[i] = null;
                        removed++;
                    } else {
                        break;
                    }
                }
                this.offset += removed;
                return removed;
            }
    
            int removeFromFirst(final int toIndex) {
                int removed = 0;
                for (int i = this.offset; i < Math.min(toIndex, this.pos); i++) {
                    this.elements[i] = null;
                    removed++;
                }
                this.offset += removed;
                return removed;
            }
    
            @Override
            public String toString() {
                StringBuilder b = new StringBuilder();
                for (int i = this.offset; i < this.pos; i++) {
                    b.append(this.elements[i]);
                    if (i != this.pos - 1) {
                        b.append(", ");
                    }
                }
                return "Segment [elements=" + b.toString() + ", offset=" + this.offset + ", pos=" + this.pos + "]";
            }
    
        }
  • 相关阅读:
    sort
    usaco-3.1-humble-pass
    usaco-3.1-inflate-pass
    usaco-3.1-agrinet-pass
    usaco-2.4-fracdec-pass
    usaco-2.4-comhome-pass
    usaco-2.4-cowtour-pass
    usaco-2.4-maze1-pass
    usaco-2.4-ttwo-pass
    usaco-2.3-concom-pass
  • 原文地址:https://www.cnblogs.com/gaojy/p/15208255.html
Copyright © 2011-2022 走看看