Netty源码 Recycler 对象池全面解析

  众所周知Netty是一个高性能的NIO通信框架, Netty开发者都是很厉害的, 不仅框架设计很精巧,针对高性能做了很多优化, 很多细节方面都处理的很好. 做中间件用C语言开发当然是速度最快的, 用Java做NIO通信中间件, 需要对java语言有很深的认识, 做到扬长弊短.
  比如Java的面向对象编程, 提高了开发的效率, 但是面向对象编程的附属品垃圾回收机制, 在高并发场景下还是一个瓶颈, 特别是Netty的I/O通信采用的是非堆内存, 对这种内存对象垃圾回收效率会比JVM的堆内存效率低, 频繁的GC对虚拟机性能有很大影响. Netty中打交道最多个就是各种Buffer, 通信I/O都是在处理Buffer对象. 因为Buf对象实在使用太频繁了, 哪怕提升一点点, 对性能也是有不少提升的.
  下面我们就来看下Netty在这方面做了哪些优化. io.netty.util.Recycler 类是Netty自定义的一个对象池, 借助于这个类可以从对象池中获取对象, 使用完了回收到对象池中, 减少GC.我现在看的版本是Netty的4.1.13.Final版, 差不多是最新的版本了. Netty的开发社区还是很活跃的, 很多代码都在持续优化中, 有bug也都是能及时修复的.比如Recycler这个类, 也是一直在持续优化中, 比老版本的类功能更强大.

1. Recycler

  这是一个抽象类, 子类继承它时需要实现 newObject(Handle handle) 方法, 因为不同的子类针对不同的对象进行池化, 具体是什么对象由子类自己实现.
内部是用一个对象数组维护缓存的对象.
1. io.netty.util.Recycler#get方法 : 是获取对象池中对象的入口, 如果有可用对象,直接返回, 没有就调用上面提到的newObject方法创建一个.
2. io.netty.util.Recycler#recycle方法: 是对象使用完毕后回收对象的, 现在已经标记@Deprecated不建议使用了, 建议使用io.netty.util.Recycler.Handle方法. 可以看下4.0.x版本中都是用的这个方法, 这个方法只能回收当前线程创建的对象,负责直接返回false不回收,交给GC处理了. 方法io.netty.util.Recycler.DefaultHandle#recycle优势就是, 可以回收不是当前线程创建的对象, 复用性和性能更好了.

2. Stack

  这是Recycler中定义的一个类, 主要也只有Recycler会访问到, Stack就是维护对象池的数据结构了.上面提到的io.netty.util.Recycler#get方法是从FastThreadLocal从获取池中对象,所以这个对象池是各个线程独立的,也就是每个线程都对应一个Stack.
  FastThreadLocal是Netty自己定义的一个类似于JDK的ThreadLocal但是性能更高的一个数据结构,ThreadLocal内部访问数据是Map型的数据访问,FastThreadLocal内部是数组,直接通过索引访问会更快.

3. WeakOrderQueue

  这个Recycler私有的一个类,用来暂存待回收的对象.
  上面提到了io.netty.util.Recycler.DefaultHandle#recycle方法,可以回收不是当前线程创建的对象. 主要就是靠这个类实现的.
  recycle方法判断,如果是当前线程创建的对象, 直接就把对象放到当前线程对应的Stack中. 如果不是, 则放入WeakOrderQueue中, 当然WeakOrderQueue会和回收的对象所对应的Stack是相关联的. 在从Stack获取对象池时,如果对象池为空,会尝试从对应的WeakOrderQueue中恢复对象,这样就实现了回收的功能. WeakOrderQueue可以有多个, 多个WeakOrderQueue是一个链表结构, 可以依次访问.
  还有个东西要注意下,由于Stack是每个线程的本地变量,所以Stack里的所有方法都是线程安全的. 具体还用到了各种线程安全问题, 还有WeakReference弱引用的使用, 以及位运算控制内存池缓慢增长 等各种细节方面都考虑的很好, 确实很厉害. 要做到对这个类有充分的理解, 需要熟悉java的GC机制, 这块我后面还要再研究一下.

4. Recycler 源码全面解析 (详细说明和注释)


/**
 * Light-weight object pool based on a thread-local stack.  // 一个轻量的对象池
 *
 * @param <T> the type of the pooled object
 */
public abstract class Recycler<T> {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);

    @SuppressWarnings("rawtypes")
    private static final Handle NOOP_HANDLE = new Handle() {    // 表示一个不需要回收的包装对象
        @Override
        public void recycle(Object object) {    // 用于maxCapacityPerThread == 0时,关闭对象回收功能.
            // NOOP
        }
    };
    private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE); // 线程安全的自增计数器,用来做唯一标记的.
    private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();    //static变量, 生成并获取一个唯一id, 标记当前的线程.
    private static final int DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD = 32768; // Use 32k instances as default.
    private static final int DEFAULT_MAX_CAPACITY_PER_THREAD;                 // 每个线程的Stack最多缓存多少个对象
    private static final int INITIAL_CAPACITY;                  // 初始化容量
    private static final int MAX_SHARED_CAPACITY_FACTOR;        // 最大可共享的容量
    private static final int MAX_DELAYED_QUEUES_PER_THREAD;     // WeakOrderQueue最大数量
    private static final int LINK_CAPACITY;                     // WeakOrderQueue中的数组DefaultHandle<?>[] elements容量
    private static final int RATIO;                             // 掩码

    static {    // 这里做到了各种参数都是可配置的, 可以根据实际的压测情况, 调节对象池的参数
        // In the future, we might have different maxCapacity for different object types.
        // e.g. io.netty.recycler.maxCapacity.writeTask
        //      io.netty.recycler.maxCapacity.outboundBuffer
        int maxCapacityPerThread = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacityPerThread",
                SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity", DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD));
        if (maxCapacityPerThread < 0) {
            maxCapacityPerThread = DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD;
        }

        DEFAULT_MAX_CAPACITY_PER_THREAD = maxCapacityPerThread;

        MAX_SHARED_CAPACITY_FACTOR = max(2,
                SystemPropertyUtil.getInt("io.netty.recycler.maxSharedCapacityFactor",
                        2));

        MAX_DELAYED_QUEUES_PER_THREAD = max(0,
                SystemPropertyUtil.getInt("io.netty.recycler.maxDelayedQueuesPerThread",
                        // We use the same value as default EventLoop number
                        NettyRuntime.availableProcessors() * 2));

        LINK_CAPACITY = safeFindNextPositivePowerOfTwo(
                max(SystemPropertyUtil.getInt("io.netty.recycler.linkCapacity", 16), 16));

        // By default we allow one push to a Recycler for each 8th try on handles that were never recycled before.      // 默认每过8次,允许回收一次
        // This should help to slowly increase the capacity of the recycler while not be too sensitive to allocation    // 可以让recycler的容量缓慢的增大,避免爆发式的请求吧.
        // bursts.
        RATIO = safeFindNextPositivePowerOfTwo(SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8));    // 值默认为8, 也就是二进制 1000

        if (logger.isDebugEnabled()) {
            if (DEFAULT_MAX_CAPACITY_PER_THREAD == 0) {
                logger.debug("-Dio.netty.recycler.maxCapacityPerThread: disabled");
                logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: disabled");
                logger.debug("-Dio.netty.recycler.linkCapacity: disabled");
                logger.debug("-Dio.netty.recycler.ratio: disabled");
            } else {
                logger.debug("-Dio.netty.recycler.maxCapacityPerThread: {}", DEFAULT_MAX_CAPACITY_PER_THREAD);
                logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: {}", MAX_SHARED_CAPACITY_FACTOR);
                logger.debug("-Dio.netty.recycler.linkCapacity: {}", LINK_CAPACITY);
                logger.debug("-Dio.netty.recycler.ratio: {}", RATIO);
            }
        }

        INITIAL_CAPACITY = min(DEFAULT_MAX_CAPACITY_PER_THREAD, 256);
    }

    private final int maxCapacityPerThread;
    private final int maxSharedCapacityFactor;
    private final int ratioMask;
    private final int maxDelayedQueuesPerThread;

    private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {     //FastThreadLocal是线程本地变量, 所以每个线程都对应一个自己的Stack.
        @Override
        protected Stack<T> initialValue() {
            return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
                    ratioMask, maxDelayedQueuesPerThread);
        }
    };

    protected Recycler() {
        this(DEFAULT_MAX_CAPACITY_PER_THREAD);
    }

    protected Recycler(int maxCapacityPerThread) {
        this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
    }

    protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
        this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
    }

    protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
                       int ratio, int maxDelayedQueuesPerThread) {
        ratioMask = safeFindNextPositivePowerOfTwo(ratio) - 1;  //根据ratio获取一个掩码,默认为8,那么ratioMask二进制就是 "111"
        if (maxCapacityPerThread <= 0) {
            this.maxCapacityPerThread = 0;
            this.maxSharedCapacityFactor = 1;
            this.maxDelayedQueuesPerThread = 0;
        } else {
            this.maxCapacityPerThread = maxCapacityPerThread;
            this.maxSharedCapacityFactor = max(1, maxSharedCapacityFactor);
            this.maxDelayedQueuesPerThread = max(0, maxDelayedQueuesPerThread);
        }
    }

    @SuppressWarnings("unchecked")
    public final T get() {
        if (maxCapacityPerThread == 0) {        // 通过修改maxCapacityPerThread=0可以关闭回收功能, 默认值是32768
            return newObject((Handle<T>) NOOP_HANDLE);
        }
        Stack<T> stack = threadLocal.get();     // 获取当前线程对应的Stack
        DefaultHandle<T> handle = stack.pop();  // 从对象池获取对象
        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);   // 没有对象,则调用子类的newObject方法创建新的对象
        }
        return (T) handle.value;
    }

    /**
     * @deprecated use {@link Handle#recycle(Object)}.  //旧的方法
     */
    @Deprecated
    public final boolean recycle(T o, Handle<T> handle) {
        if (handle == NOOP_HANDLE) {
            return false;
        }

        DefaultHandle<T> h = (DefaultHandle<T>) handle;
        if (h.stack.parent != this) {       // 旧的方法,如果不是当前线程的, 直接不回收了.
            return false;
        }

        h.recycle(o);
        return true;
    }

    final int threadLocalCapacity() {
        return threadLocal.get().elements.length;
    }

    final int threadLocalSize() {
        return threadLocal.get().size;
    }

    protected abstract T newObject(Handle<T> handle);

    public interface Handle<T> {
        void recycle(T object);
    }

    static final class DefaultHandle<T> implements Handle<T> {  // DefaultHandle就是就是Stack的包装对象,持有stack的引用,可以回收自己到stack中;
        private int lastRecycledId; //标记最新一次回收的线程id
        private int recycleId;      //也是一个标记,是用来回收前的校验的.

        boolean hasBeenRecycled;    //标记是否已经被回收

        private Stack<?> stack;     //持有stack的引用
        private Object value;

        DefaultHandle(Stack<?> stack) {
            this.stack = stack;
        }

        @Override
        public void recycle(Object object) {
            if (object != value) {
                throw new IllegalArgumentException("object does not belong to handle");
            }
            stack.push(this);   //可以回收自己到stack中
        }
    }

    private static final FastThreadLocal<Map<Stack<?>, WeakOrderQueue>> DELAYED_RECYCLED =      // 这也是一个线程本地变量,每个线程都有自己的Map<Stack<?>, WeakOrderQueue>
            new FastThreadLocal<Map<Stack<?>, WeakOrderQueue>>() {                              // 根据Stack可以获取到对应的WeakOrderQueue
        @Override                                                                               // 需要注意的是这边两个对象都有弱引用,WeakReference! 具体下面解释.
        protected Map<Stack<?>, WeakOrderQueue> initialValue() {
            return new WeakHashMap<Stack<?>, WeakOrderQueue>();     // 使用WeakHashMap,保证对key也就是Stack是弱引用; 一旦Stack没有强引用了, 会被回收的,WeakHashMap不会无限占用内存;
        }
    };

    // a queue that makes only moderate guarantees about visibility: items are seen in the correct order,
    // but we aren't absolutely guaranteed to ever see anything at all, thereby keeping the queue cheap to maintain
    private static final class WeakOrderQueue {

        static final WeakOrderQueue DUMMY = new WeakOrderQueue();   //用于标记空的WeakOrderQueue,在达到WeakOrderQueue数量上限时放入一个这个,表示结束了.

        // Let Link extend AtomicInteger for intrinsics. The Link itself will be used as writerIndex.   // Link对象本身会作为读索引.
        @SuppressWarnings("serial")
        private static final class Link extends AtomicInteger {     //这里为什么要继承一个AtomicInteger呢,因为这样Link就是一个线程安全的容器,保证了多线程安全和可见性.
            private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];   //维护一个数组, 容量默认为16.

            private int readIndex;      //读索引
            private Link next;          //下一个索引. WeakOrderQueue有多个时, 之间遍历靠next指向下一个WeakOrderQueue.
        }

        // chain of data items
        private Link head, tail;        //头指针和尾指针
        // pointer to another queue of delayed items for the same stack
        private WeakOrderQueue next;    //指向下一个WeakOrderQueue
        private final WeakReference<Thread> owner;              // 拥有者,干嘛的?? 要注意到这是一个弱引用,就是不会影响Thread对象的GC的,如果thread为空,owner.get()会返回null
        private final int id = ID_GENERATOR.getAndIncrement();  // WeakOrderQueue的唯一标记
        private final AtomicInteger availableSharedCapacity;    // 允许的最大共享容量

        private WeakOrderQueue() {      //用于初始化DUMMY,遇到DUMMY就知道要抛弃了.
            owner = null;
            availableSharedCapacity = null;
        }

        private WeakOrderQueue(Stack<?> stack, Thread thread) {     //在Stack的io.netty.util.Recycler.Stack.pushLater()中如果没有WeakOrderQueue,会调用这里new一个
            head = tail = new Link();                   //初始化头和尾指针,指向这个新创建的Link
            owner = new WeakReference<Thread>(thread);  //表示当前的WeakOrderQueue是被哪个线程拥有的. 因为只有不同线程去回收对象才会进到这个方法,所以thread不是这stack对应的线程
                                                        //这里的WeakReference,对Thread是一个弱引用,所以Thread在没有强引用时就会被回收(线程也是可以回收的对象)
            // Its important that we not store the Stack itself in the WeakOrderQueue as the Stack also is used in  //这里很重要,我们没有把Stack保存到WeakOrderQueue中
            // the WeakHashMap as key. So just store the enclosed AtomicInteger which should allow to have the      //因为Stack是WeakHashMap的key
            // Stack itself GCed.                                                                                   //我们只是持有head 和 tail的引用,就可以遍历WeakOrderQueue
            availableSharedCapacity = stack.availableSharedCapacity;
        }

        static WeakOrderQueue newQueue(Stack<?> stack, Thread thread) { //stack.setHead(queue)必须在构造器外进行,防止对象溢出.(我查看作者的该动记录是为了修改以前的不安全发布的构造方法)
            WeakOrderQueue queue = new WeakOrderQueue(stack, thread);
            // Done outside of the constructor to ensure WeakOrderQueue.this does not escape the constructor and so
            // may be accessed while its still constructed.
            stack.setHead(queue);   //这个stack,头指针指向 这个新创建的WeakOrderQueue
            return queue;
        }

        private void setNext(WeakOrderQueue next) {
            assert next != this;
            this.next = next;
        }

        /**
         * Allocate a new {@link WeakOrderQueue} or return {@code null} if not possible.
         */
        static WeakOrderQueue allocate(Stack<?> stack, Thread thread) {
            // We allocated a Link so reserve the space
            return reserveSpace(stack.availableSharedCapacity, LINK_CAPACITY)   //先预约space容量
                    ? WeakOrderQueue.newQueue(stack, thread) : null;            //预约成功, 对当前stack创建一个新的WeakOrderQueue
        }

        private static boolean reserveSpace(AtomicInteger availableSharedCapacity, int space) {     //容量不够就返回false; 够的话就减去space大小.
            assert space >= 0;
            for (;;) {
                int available = availableSharedCapacity.get();
                if (available < space) {    //如果剩余可用容量小于 LINK_CAPACITY,返回false
                    return false;
                }
                if (availableSharedCapacity.compareAndSet(available, available - space)) {    //调用availableSharedCapacity线程安全的CAS方法
                    return true;
                }
            }
        }

        private void reclaimSpace(int space) {          //availableSharedCapacity加上space,就是恢复前面减去的space大小
            assert space >= 0;
            availableSharedCapacity.addAndGet(space);   //availableSharedCapacity和上面的方法会存在并发,所以采用原子类型.
        }

        void add(DefaultHandle<?> handle) {
            handle.lastRecycledId = id;     //更新最近一次回收的id, 注意这里只更新了lastRecycledId, recycleId没有更新, 等到真正回收的时候,会改成一致的.

            Link tail = this.tail;
            int writeIndex;
            if ((writeIndex = tail.get()) == LINK_CAPACITY) {
                if (!reserveSpace(availableSharedCapacity, LINK_CAPACITY)) {    //判断剩余空间是否足够
                    // Drop it.
                    return;
                }
                // We allocate a Link so reserve the space
                this.tail = tail = tail.next = new Link();

                writeIndex = tail.get();        //tail这是一个自增的变量,每次tail.get()就表示放到末尾了
            }
            tail.elements[writeIndex] = handle; //把对应的handle引用放到末尾的数组里
            handle.stack = null;
            // we lazy set to ensure that setting stack to null appears before we unnull it in the owning thread;
            // this also means we guarantee visibility of an element in the queue if we see the index updated
            tail.lazySet(writeIndex + 1);   //todo 这个方法JDK注释比较少,还没看懂.后面可以写个demo测试下.
        }

        boolean hasFinalData() {
            return tail.readIndex != tail.get();    //readIndex指向当前读取的, tail.get()表示最大的值, 不相等代表还有待读取的数据.
        }

        // transfer as many items as we can from this queue to the stack, returning true if any were transferred
        @SuppressWarnings("rawtypes")
        boolean transfer(Stack<?> dst) {    //把WeakOrderQueue里面暂存的对象,传输到对应的stack,主动去回收对象.
            Link head = this.head;
            if (head == null) {
                return false;
            }

            if (head.readIndex == LINK_CAPACITY) {
                if (head.next == null) {
                    return false;
                }
                this.head = head = head.next;
            }

            final int srcStart = head.readIndex;
            int srcEnd = head.get();
            final int srcSize = srcEnd - srcStart;
            if (srcSize == 0) {
                return false;
            }

            final int dstSize = dst.size;
            final int expectedCapacity = dstSize + srcSize;

            if (expectedCapacity > dst.elements.length) {
                final int actualCapacity = dst.increaseCapacity(expectedCapacity);  //扩容
                srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd);
            }

            if (srcStart != srcEnd) {
                final DefaultHandle[] srcElems = head.elements;
                final DefaultHandle[] dstElems = dst.elements;
                int newDstSize = dstSize;
                for (int i = srcStart; i < srcEnd; i++) {
                    DefaultHandle element = srcElems[i];
                    if (element.recycleId == 0) {
                        element.recycleId = element.lastRecycledId;     //前面的add方法只更新了lastRecycledId, transfer执行好了,需要更新recycleId一致,表示回收成功.
                    } else if (element.recycleId != element.lastRecycledId) {   //recycleId=0才表示可回收的
                        throw new IllegalStateException("recycled already");
                    }
                    srcElems[i] = null;             //成功了,就把WeakOrderQueue数组里置为空,释放对对象的引用

                    if (dst.dropHandle(element)) {  //判断是否回收
                        // Drop the object.
                        continue;
                    }
                    element.stack = dst;                //element是Link数组里的对象,stack指向目标stack
                    dstElems[newDstSize ++] = element;  //目标Stack数组的尾部, 放入element
                }

                if (srcEnd == LINK_CAPACITY && head.next != null) {     //如果head.next还有,就需要继续扩容
                    // Add capacity back as the Link is GCed.
                    reclaimSpace(LINK_CAPACITY);    //扩容

                    this.head = head.next;          //指向下一个,等待下一次循环继续上面的操作.transfer方法外层是被循环调用的.
                }

                head.readIndex = srcEnd;            //下次从这里开始读
                if (dst.size == newDstSize) {       //如果相等则表示没有剩余空间了,返回false
                    return false;
                }
                dst.size = newDstSize;              //目标数组size修改
                return true;
            } else {
                // The destination stack is full already.   // 目标仍然是满的,直接返回false,就不做回收动作
                return false;
            }
        }

        @Override
        protected void finalize() throws Throwable {    //WeakOrderQueue对象GC前调用这个方法
            try {
                super.finalize();   //回收对象
            } finally {
                // We need to reclaim all space that was reserved by this WeakOrderQueue so we not run out of space in
                // the stack. This is needed as we not have a good life-time control over the queue as it is used in a  //需要这个方法是因为这个被用在WeakHashMap中,会随时GC它
                // WeakHashMap which will drop it at any time.
                Link link = head;
                while (link != null) {  //遍历WeakHashMap中所有的Link,直到link = null这样里面的Link对象没有引用了,都会被回收.
                    reclaimSpace(LINK_CAPACITY);
                    link = link.next;
                }
            }
        }
    }

    static final class Stack<T> {

        // we keep a queue of per-thread queues, which is appended to once only, each time a new thread other
        // than the stack owner recycles: when we run out of items in our stack we iterate this collection
        // to scavenge those that can be reused. this permits us to incur minimal thread synchronisation whilst     //使用最少的同步操作,并且可以全部回收.
        // still recycling all items.
        final Recycler<T> parent;
        final Thread thread;                            //持有线程的强引用, 如果Stack没有被回收,那么Thread也不能被回收了,但是Stack没有强引用,在map中是弱引用,前面提到的.关于引用的知识回头再细化下.
        final AtomicInteger availableSharedCapacity;    //容量,用一个AtomicInteger表示,是为了可以并发CAS修改;
        final int maxDelayedQueues;

        private final int maxCapacity;
        private final int ratioMask;
        private DefaultHandle<?>[] elements;
        private int size;
        private int handleRecycleCount = -1;    // Start with -1 so the first one will be recycled.
        private WeakOrderQueue cursor, prev;    // 指向当前的WeakOrderQueue 和 前一个
        private volatile WeakOrderQueue head;

        Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
              int ratioMask, int maxDelayedQueues) {
            this.parent = parent;
            this.thread = thread;
            this.maxCapacity = maxCapacity;
            availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY)); //maxSharedCapacityFactor默认为2
            elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];   //取初始值和maxCapacity较小的一个; 如果INITIAL_CAPACITY < maxCapacity后面可以动态扩容
            this.ratioMask = ratioMask;
            this.maxDelayedQueues = maxDelayedQueues;
        }

        // Marked as synchronized to ensure this is serialized. //标记为同步,保证两个操作顺序执行
        synchronized void setHead(WeakOrderQueue queue) {   // 重要的一点就是这个方法是 synchronized 的, 这个类里面唯一的synchronized方法
            queue.setNext(head);                            // synchronized避免并发修改queue.setNext的情况.
            head = queue;
        }

        int increaseCapacity(int expectedCapacity) {
            int newCapacity = elements.length;
            int maxCapacity = this.maxCapacity;
            do {
                newCapacity <<= 1;  //每次扩容两倍,直到newCapacity大于expectedCapacity
            } while (newCapacity < expectedCapacity && newCapacity < maxCapacity);

            newCapacity = min(newCapacity, maxCapacity);
            if (newCapacity != elements.length) {
                elements = Arrays.copyOf(elements, newCapacity);
            }

            return newCapacity;
        }

        @SuppressWarnings({ "unchecked", "rawtypes" })
        DefaultHandle<T> pop() {
            int size = this.size;
            if (size == 0) {
                if (!scavenge()) {
                    return null;
                }
                size = this.size;
            }
            size --;
            DefaultHandle ret = elements[size];
            elements[size] = null;
            if (ret.lastRecycledId != ret.recycleId) {  //这两个应该相等
                throw new IllegalStateException("recycled multiple times");
            }
            ret.recycleId = 0;          //获取出的对象,置为0表示没有被回收
            ret.lastRecycledId = 0;     //获取出的对象,置为0表示没有被回收
            this.size = size;
            return ret;
        }

        boolean scavenge() {
            // continue an existing scavenge, if any
            if (scavengeSome()) {
                return true;
            }

            // reset our scavenge cursor
            prev = null;
            cursor = head;
            return false;
        }

        boolean scavengeSome() {    //尝试回收
            WeakOrderQueue prev;
            WeakOrderQueue cursor = this.cursor;    //指向当前的指针
            if (cursor == null) {                   //当前为null,就指向head,head也为null就跳出返回false
                prev = null;
                cursor = head;
                if (cursor == null) {
                    return false;
                }
            } else {
                prev = this.prev;
            }

            boolean success = false;
            do {
                if (cursor.transfer(this)) {
                    success = true;
                    break;
                }
                WeakOrderQueue next = cursor.next;
                if (cursor.owner.get() == null) {   //线程被回收了
                    // If the thread associated with the queue is gone, unlink it, after                //cursor.owner.get() == null表示,WeakOrderQueue的归属线程被回收了.
                    // performing a volatile read to confirm there is no data left to collect.          //这里读取的是线程安全的变量,确认没有数据可回收了
                    // We never unlink the first queue, as we don't want to synchronize on updating the head.   //第一个queue永远不回收,因为更新head指针会存在并发.
                    if (cursor.hasFinalData()) {
                        for (;;) {
                            if (cursor.transfer(this)) {
                                success = true;
                            } else {
                                break;  //cursor.transfer(this)返回false,代表没有读取的数据了
                            }
                        }
                    }

                    if (prev != null) {
                        prev.setNext(next);     //这是一个单向链表,只要改变prev的引用,老的节点会被回收的.
                    }
                } else {
                    prev = cursor;
                }

                cursor = next;

            } while (cursor != null && !success);

            this.prev = prev;
            this.cursor = cursor;
            return success;
        }

        void push(DefaultHandle<?> item) {  //会综合判断,如果是当前线程,直接放进数组中,如果不是,就先报错到WeakOrderQueue中.
            Thread currentThread = Thread.currentThread();
            if (thread == currentThread) {
                // The current Thread is the thread that belongs to the Stack, we can try to push the object now.
                pushNow(item);
            } else {
                // The current Thread is not the one that belongs to the Stack, we need to signal that the push     //保存到WeakOrderQueue,等待回收.
                // happens later.
                pushLater(item, currentThread);
            }
        }

        private void pushNow(DefaultHandle<?> item) {               // 立即push,把item对象回收到elements数组中
            if ((item.recycleId | item.lastRecycledId) != 0) {      // 如果没回收,recycleId和lastRecycledId应该都是0; 正常应该不会进来, 感觉应该是作者为了在开发中排除这种情况.
                throw new IllegalStateException("recycled already");
            }
            item.recycleId = item.lastRecycledId = OWN_THREAD_ID;   //都更新为OWN_THREAD_ID,表示被回收过了

            int size = this.size;
            if (size >= maxCapacity || dropHandle(item)) {          //如果size >= maxCapacity, 就会执行dropHandle()
                // Hit the maximum capacity or should drop - drop the possibly youngest object.
                return;                                             //dropHandle()返回true,就直接return掉,本次不做回收.
            }
            if (size == elements.length) {                          //如果size == elements.length,就要对elements数组进行扩容,每次扩容2倍,最大到maxCapacity
                elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
            }

            elements[size] = item;      //这里要注意: elements.length是数组的长度,包括空位; size是数组中有内容的长度, 这里是在最末尾放item;
            this.size = size + 1;       //size+1
        }

        private void pushLater(DefaultHandle<?> item, Thread thread) {  // 想想为什么需要pushLater?
            // we don't want to have a ref to the queue as the value in our weak map
            // so we null it out; to ensure there are no races with restoring it later  //为了在回收的过程中没有并发,如果回收的不是当前线程的Stack的对象,
            // we impose a memory ordering here (no-op on x86)                          //就放入到它的WeakOrderQueue,等它自己拿的时候回收,这样recycle方法就没有并发了;这种思想在Doug lea的AQS里也有.
            Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();     //获取当前线程对应的Map<Stack<?>, WeakOrderQueue>
            WeakOrderQueue queue = delayedRecycled.get(this);                           //根据this Stack获取 WeakOrderQueue
            if (queue == null) {                                        //如果queue就需要创建一个
                if (delayedRecycled.size() >= maxDelayedQueues) {       //大于上限,就放入一个DUMMY,表示满了
                    // Add a dummy queue so we know we should drop the object
                    delayedRecycled.put(this, WeakOrderQueue.DUMMY);
                    return;
                }
                // Check if we already reached the maximum number of delayed queues and if we can allocate at all.
                if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {      //WeakOrderQueue.allocate方法,针对需要回收的这个Stack,创建一个新的WeakOrderQueue
                    // drop object
                    return;
                }
                delayedRecycled.put(this, queue);
            } else if (queue == WeakOrderQueue.DUMMY) {
                // drop object
                return;
            }

            queue.add(item);
        }

        boolean dropHandle(DefaultHandle<?> handle) {
            if (!handle.hasBeenRecycled) {                      //判断是否已经回收
                if ((++handleRecycleCount & ratioMask) != 0) {  //handleRecycleCount初始为-1, ++handleRecycleCount = 0, 所以第一次肯定会进去.位运算的性能很好.
                    // Drop the object.                         //ratioMask是一个掩码,解释见下方 
                    return true;
                }
                handle.hasBeenRecycled = true;
            }
            return false;
        }

        DefaultHandle<T> newHandle() {
            return new DefaultHandle<T>(this);
        }
    }
}
注:

dropHandle方法里有用到一个掩码ratioMask, 这个必须是2的次方-1,
如果按默认值7 (“111”) , 只要低三位不全0, 就会返回true本次忽略不做回收. 所以返回true概率是 7/8, 目的是为了让回收动作缓慢一些, 内存池慢慢的增加, 减少对系统的压力. 不得不说作者考虑的真仔细.

1
10
11
100
101
110
111
1000 <--
1001
1010
1011
1100
1101
1110
1111
10000 <--

5. 下面写个Demo,看下效果

package comm;

import com.github.ltsopensource.core.support.SystemClock;
import io.netty.util.Recycler;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class RecyclerTest {

    static class WrapRecycler {

        private List<String> list;

        private final static Recycler<WrapRecycler> RECYCLER = new Recycler<WrapRecycler>() {
            @Override
            protected WrapRecycler newObject(Handle<WrapRecycler> handle) {
                return new WrapRecycler(handle);
            }
        };

        Recycler.Handle<WrapRecycler> handle;

        WrapRecycler(Recycler.Handle<WrapRecycler> handle) {
            this.handle = handle;
            this.list = new ArrayList<>(1000);
        }

        List<String> getList() {
            return list;
        }

        static WrapRecycler getInstance() {
            return RECYCLER.get();
        }

        void recycle() {
            handle.recycle(this);
        }
    }

    @Test
    public void testDifferentThreadRecycle() throws InterruptedException, IOException {
        System.out.println("Main thread started ...");
        final WrapRecycler instance = WrapRecycler.getInstance();
        instance.getList().add("111");      // main 线程放入一个字符串
        final CountDownLatch countDownLatch = new CountDownLatch(1);

        new Thread(new Runnable() {         // 这里新创建一个线程,在新的线程中可以回收main线程中的对象.
            @Override
            public void run() {
                System.out.println("Sub thread started ...");

                List<String> list = instance.getList();
                list.add("222");            // 子线程放入一个字符串.

                instance.recycle();         // 对main线程从对象池中回去的对象家进行回收动作.

                System.out.println("Sub Thread get list : " + WrapRecycler.getInstance().getList());    // 在子线程中从对象池获取对象
                countDownLatch.countDown();
            }
        }).start();

        countDownLatch.await();

        System.out.println("Main Thread get list : " + WrapRecycler.getInstance().getList());           // 在主线程中从对象池获取对象
        System.in.read();
    }
}
执行结果:

  可以看到执行结果, 子线程可以回收主线程从主线程对象池中的对象, 但是只是回收到主线程对应的对象池里了, 各个线程对应的对象池时独立的.

Main thread started ...
Sub thread started ...
Sub Thread get list : []
Main Thread get list : [111, 222]

  进而可以写两个demo,比较下使用对象池和依赖JVM垃圾回收的执行效率.
  我本地测试下来, 发现同样都是在堆内存下, 如果创建的都是很小的对象, 使用netty的这个对象池没有什么优势, 但是如果创建的是比较复杂比较大的对象, 使用对象池执行时间只有前者的七分之一. 理论上, 对象垃圾回收的成本越高, 这个对象池的效果就会越明显的, 特别是在Netty的非堆内存场景下, 垃圾回收的成本会更高.
  大家如果在代码里要使用的话, 可以针对自己的场景进行测试下.

6. 思考

  1. 在学习一些优秀的开源软件代码时, 我们不一定就要自己再写一套中间件, 但是其中的某些优点和思路在平时的开发中是值得借鉴的, 比如在做相关的网络编程时, 如果对netty的实现有一定的了解, 就能把一些好的设计思路用起来.
  2. 这个类的主要作者就是netty的一位核心开发人员: normanmaurer, 现在就职于苹果. 在研究这个类时, 由于注释很少, 代码晦涩难懂. 我在学习这个类时, 翻看了netty的各个版本, 从github的提交记录可以看到这个类最早创建于2013-5-28日, 其实在netty3.x的版本中是没有这个类的, 从4.x开始的版本中增加了这个类, 用于提升netty的性能. 从2013年到2017年, 这个类从无到有, 从简单到复杂, 一直在持续优化中. 在研究代码的过程中,我通过对比github上的历史代码, 看起来就相对好理解一些了, 一些复杂的实现其实不是刚开始就这么复杂的, 都是每次一点点的增强.
  3. 前面学习JDK的源码,也发现了这样规律, 比如很多concurrent包中的类从1.5就有了,但是后续的jdk版本中都在持续优化, 代码会变的比较复杂, 我在先看了JDK1.5之后, 再看1.6和1.7,就能明白一些地方作者的用意了.
  4. 一个功能点想出来就是一个好的开始, 实现出来然后需要在后续的实际应用中不断的优化和增强, 代码开发永远不是一蹴而就的, 不一定非要一次就把所有的点都想全, 好的实现可以从一个简单的想法开始.
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值