Netty源碼分析-PoolThreadCache

 

 


final class PoolThreadCache {

    final PoolArena<byte[]> heapArena;
    final PoolArena<ByteBuffer> directArena;

    //分別存儲堆外和堆內的內存,MemoryRegionCache內部結構是鏈表
    private final MemoryRegionCache<byte[]>[] tinySubPageHeapCaches; //默認長度32
    private final MemoryRegionCache<byte[]>[] smallSubPageHeapCaches; //默認長度4
    private final MemoryRegionCache<ByteBuffer>[] tinySubPageDirectCaches; //默認長度32
    private final MemoryRegionCache<ByteBuffer>[] smallSubPageDirectCaches;//默認長度4
    private final MemoryRegionCache<byte[]>[] normalHeapCaches; //默認長度3
    private final MemoryRegionCache<ByteBuffer>[] normalDirectCaches; //默認長度3

    // Used for bitshifting when calculate the index of normal caches later
    //移位使用的偏移量,在計算normalCaches數組下標時使用
    private final int numShiftsNormalDirect; //13
    private final int numShiftsNormalHeap;  //13
    private final int freeSweepAllocationThreshold; //8192

    private final AtomicBoolean freed = new AtomicBoolean();

    private int allocations;


    PoolThreadCache(PoolArena<byte[]> heapArena, PoolArena<ByteBuffer> directArena,
                    int tinyCacheSize, int smallCacheSize, int normalCacheSize,
                    int maxCachedBufferCapacity, int freeSweepAllocationThreshold) {
        if (maxCachedBufferCapacity < 0) {
            throw new IllegalArgumentException("maxCachedBufferCapacity: "
                    + maxCachedBufferCapacity + " (expected: >= 0)");
        }
        this.freeSweepAllocationThreshold = freeSweepAllocationThreshold;
        this.heapArena = heapArena;
        this.directArena = directArena;
        if (directArena != null) {
            tinySubPageDirectCaches = createSubPageCaches(
                    tinyCacheSize, PoolArena.numTinySubpagePools, SizeClass.Tiny);
            smallSubPageDirectCaches = createSubPageCaches(
                    smallCacheSize, directArena.numSmallSubpagePools, SizeClass.Small);

            numShiftsNormalDirect = log2(directArena.pageSize);
            normalDirectCaches = createNormalCaches(
                    normalCacheSize, maxCachedBufferCapacity, directArena);

            directArena.numThreadCaches.getAndIncrement();
        } else {
            // No directArea is configured so just null out all caches
            tinySubPageDirectCaches = null;
            smallSubPageDirectCaches = null;
            normalDirectCaches = null;
            numShiftsNormalDirect = -1;
        }
        if (heapArena != null) {
            // Create the caches for the heap allocations
            tinySubPageHeapCaches = createSubPageCaches(
                    tinyCacheSize, PoolArena.numTinySubpagePools, SizeClass.Tiny);
            smallSubPageHeapCaches = createSubPageCaches(
                    smallCacheSize, heapArena.numSmallSubpagePools, SizeClass.Small);

            numShiftsNormalHeap = log2(heapArena.pageSize);
            normalHeapCaches = createNormalCaches(
                    normalCacheSize, maxCachedBufferCapacity, heapArena);

            heapArena.numThreadCaches.getAndIncrement();
        } else {
            // No heapArea is configured so just null out all caches
            tinySubPageHeapCaches = null;
            smallSubPageHeapCaches = null;
            normalHeapCaches = null;
            numShiftsNormalHeap = -1;
        }

        // Only check if there are caches in use.
        if ((tinySubPageDirectCaches != null || smallSubPageDirectCaches != null || normalDirectCaches != null
                || tinySubPageHeapCaches != null || smallSubPageHeapCaches != null || normalHeapCaches != null)
                && freeSweepAllocationThreshold < 1) {
            throw new IllegalArgumentException("freeSweepAllocationThreshold: "
                    + freeSweepAllocationThreshold + " (expected: > 0)");
        }
    }

    //創建緩存數組,numCaches爲數組長度,cacheSize爲隊列長度
    private static <T> MemoryRegionCache<T>[] createSubPageCaches(
            int cacheSize, int numCaches, SizeClass sizeClass) {
        if (cacheSize > 0 && numCaches > 0) {
            //初始化數組
            MemoryRegionCache<T>[] cache = new MemoryRegionCache[numCaches];
            for (int i = 0; i < cache.length; i++) {
                //數組元素賦值,SubPageMemoryRegionCache內部包含一個隊列,存儲PoolChunk
                //cacheSize=隊列容量,sizeClass=爲Tiny或Small
                cache[i] = new SubPageMemoryRegionCache<T>(cacheSize, sizeClass);
            }
            return cache;
        } else {
            return null;
        }
    }

    //cacheSize默認64 maxCachedBufferCapacity默認32768(8192*4)
    private static <T> MemoryRegionCache<T>[] createNormalCaches(
            int cacheSize, int maxCachedBufferCapacity, PoolArena<T> area) {
        if (cacheSize > 0 && maxCachedBufferCapacity > 0) {
            //max=32768
            int max = Math.min(area.chunkSize, maxCachedBufferCapacity);
            //arraySize=3, log2(N),其實就是 N除以2的結果
            int arraySize = Math.max(1, log2(max / area.pageSize) + 1);

            MemoryRegionCache<T>[] cache = new MemoryRegionCache[arraySize];
            for (int i = 0; i < cache.length; i++) {
                //cacheSize=64默認,爲隊列的容量
                cache[i] = new NormalMemoryRegionCache<T>(cacheSize);
            }
            return cache;
        } else {
            return null;
        }
    }

    //val除以2的結果
    private static int log2(int val) {
        int res = 0;
        while (val > 1) {
            val >>= 1;
            res++;
        }
        return res;
    }
    
    boolean allocateTiny(PoolArena<?> area, PooledByteBuf<?> buf, int reqCapacity, int normCapacity) {
        return allocate(cacheForTiny(area, normCapacity), buf, reqCapacity);
    }

    boolean allocateSmall(PoolArena<?> area, PooledByteBuf<?> buf, int reqCapacity, int normCapacity) {
        return allocate(cacheForSmall(area, normCapacity), buf, reqCapacity);
    }

    boolean allocateNormal(PoolArena<?> area, PooledByteBuf<?> buf, int reqCapacity, int normCapacity) {
        return allocate(cacheForNormal(area, normCapacity), buf, reqCapacity);
    }

    //分配緩存
    private boolean allocate(MemoryRegionCache<?> cache, PooledByteBuf buf, int reqCapacity) {
        if (cache == null) {
            // no cache found so just return false here
            return false;
        }
        //分配緩存
        boolean allocated = cache.allocate(buf, reqCapacity);
        //分配次數>=8192
        if (++ allocations >= freeSweepAllocationThreshold) {
            allocations = 0;
            //釋放掉緩存
            trim();
        }
        return allocated;
    }

    //把PoolChunk根據大小不同,選擇對應的MemoryRegionCache,然後加入到隊列
    boolean add(PoolArena<?> area, PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass) {
        MemoryRegionCache<?> cache = cache(area, normCapacity, sizeClass);
        if (cache == null) {
            return false;
        }
        return cache.add(chunk, handle);
    }

    //根據請求大小,選擇對應的緩存對象
    private MemoryRegionCache<?> cache(PoolArena<?> area, int normCapacity, SizeClass sizeClass) {
        switch (sizeClass) {
        case Normal:
            return cacheForNormal(area, normCapacity);
        case Small:
            return cacheForSmall(area, normCapacity);
        case Tiny:
            return cacheForTiny(area, normCapacity);
        default:
            throw new Error();
        }
    }

    //當前Cache被垃圾回收時會被調用
    @Override
    protected void finalize() throws Throwable {
        try {
            super.finalize();
        } finally {
            free();
        }
    }

   //釋放所有資源
    void free() {
        //釋放所有資源,線程安全判斷,只釋放一次
        if (freed.compareAndSet(false, true)) {
            int numFreed = free(tinySubPageDirectCaches) +
                    free(smallSubPageDirectCaches) +
                    free(normalDirectCaches) +
                    free(tinySubPageHeapCaches) +
                    free(smallSubPageHeapCaches) +
                    free(normalHeapCaches);

            //directArena線程引用計數器減一
            if (directArena != null) {
                directArena.numThreadCaches.getAndDecrement();
            }

            //heapArena線程引用計數器減一
            if (heapArena != null) {
                heapArena.numThreadCaches.getAndDecrement();
            }
        }
    }

    //釋放緩存數組
    private static int free(MemoryRegionCache<?>[] caches) {
        if (caches == null) {
            return 0;
        }

        int numFreed = 0;
        for (MemoryRegionCache<?> c: caches) {
            numFreed += free(c);
        }
        return numFreed;
    }

    //把緩存內部隊列中所有chunk釋放掉
    private static int free(MemoryRegionCache<?> cache) {
        if (cache == null) {
            return 0;
        }
        return cache.free();
    }

    //把所有類型的緩存數組全部釋放一遍,具體釋放邏輯看其實現
    void trim() {
        trim(tinySubPageDirectCaches);
        trim(smallSubPageDirectCaches);
        trim(normalDirectCaches);
        trim(tinySubPageHeapCaches);
        trim(smallSubPageHeapCaches);
        trim(normalHeapCaches);
    }

    //釋放caches數組
    private static void trim(MemoryRegionCache<?>[] caches) {
        if (caches == null) {
            return;
        }
        //循環每個cache元素釋放
        for (MemoryRegionCache<?> c: caches) {
            trim(c);
        }
    }

    private static void trim(MemoryRegionCache<?> cache) {
        if (cache == null) {
            return;
        }
        cache.trim();
    }

    private MemoryRegionCache<?> cacheForTiny(PoolArena<?> area, int normCapacity) {
        //normCapacity >>> 4;  根據normCapacity計算出tiny緩存數組下標
        //數組長度32,每個元素對應不用的大小,從16個字節大小開始,每次增加16個字節。
        int idx = PoolArena.tinyIdx(normCapacity);
        if (area.isDirect()) {
            return cache(tinySubPageDirectCaches, idx);
        }
        return cache(tinySubPageHeapCaches, idx);
    }

    private MemoryRegionCache<?> cacheForSmall(PoolArena<?> area, int normCapacity) {
        //根據normCapacity計算small緩存數組下標,數組長度爲4,[512,1024,2048,4096]
        int idx = PoolArena.smallIdx(normCapacity);
        if (area.isDirect()) {
            return cache(smallSubPageDirectCaches, idx);
        }
        return cache(smallSubPageHeapCaches, idx);
    }

    private MemoryRegionCache<?> cacheForNormal(PoolArena<?> area, int normCapacity) {
        if (area.isDirect()) {
            //numShiftsNormalDirect默認爲13,相當於除以8192
            //這裏如果idx不大於3的話,那麼normCapacity最大爲5*8192
            int idx = log2(normCapacity >> numShiftsNormalDirect);
            return cache(normalDirectCaches, idx);
        }
        int idx = log2(normCapacity >> numShiftsNormalHeap);
        return cache(normalHeapCaches, idx);
    }

    private static <T> MemoryRegionCache<T> cache(MemoryRegionCache<T>[] cache, int idx) {
        //如果下標越界返回null
        if (cache == null || idx > cache.length - 1) {
            return null;
        }
        return cache[idx];
    }

    //TINY or SMALL 大小的緩存,使用Subpage來分配
    private static final class SubPageMemoryRegionCache<T> extends MemoryRegionCache<T> {
        SubPageMemoryRegionCache(int size, SizeClass sizeClass) {
            super(size, sizeClass);
        }

        @Override
        protected void initBuf(
                PoolChunk<T> chunk, long handle, PooledByteBuf<T> buf, int reqCapacity) {
            chunk.initBufWithSubpage(buf, handle, reqCapacity);
        }
    }

    //Normal大小的緩存,使用chunk.initBuf按整塊分配
    private static final class NormalMemoryRegionCache<T> extends MemoryRegionCache<T> {
        NormalMemoryRegionCache(int size) {
            super(size, SizeClass.Normal);
        }

        //按整塊分配
        @Override
        protected void initBuf(
                PoolChunk<T> chunk, long handle, PooledByteBuf<T> buf, int reqCapacity) {
            chunk.initBuf(buf, handle, reqCapacity);
        }
    }

    //緩存元素,內部一個隊列存儲每個PoolChunk
    private abstract static class MemoryRegionCache<T> {
        private final int size;
        private final Queue<Entry<T>> queue;
        private final SizeClass sizeClass;
        private int allocations;

        MemoryRegionCache(int size, SizeClass sizeClass) {
            //以2的次方進行增長,比如傳入3返回4,傳入5返回8,傳入9返回16。
            this.size = MathUtil.safeFindNextPositivePowerOfTwo(size);
            //定長隊列
            queue = PlatformDependent.newFixedMpscQueue(this.size);
            //緩存類型 tiny small normal
            this.sizeClass = sizeClass;
        }

        //初始化PooledByteBuf,子類實現,根據tiny,small或Normal有不同的處理方式
        protected abstract void initBuf(PoolChunk<T> chunk, long handle,
                                        PooledByteBuf<T> buf, int reqCapacity);

        //把chunk加入隊列,如果隊列滿了返回false
        public final boolean add(PoolChunk<T> chunk, long handle) {
            //創建Entry
            Entry<T> entry = newEntry(chunk, handle);

            //隊列滿了返回false
            boolean queued = queue.offer(entry);
            if (!queued) {
               //加入失敗回收entry
                entry.recycle();
            }
            return queued;
        }

        //分配內存
        public final boolean allocate(PooledByteBuf<T> buf, int reqCapacity) {
            //獲取並移除元素,元素不存在返回false
            Entry<T> entry = queue.poll();
            if (entry == null) {
                return false;
            }
            //元素存在則一定分配成功
            initBuf(entry.chunk, entry.handle, buf, reqCapacity);

            //回收entry
            entry.recycle();

            //分配數量增加
            ++ allocations;
            return true;
        }

        //把隊列中所有元素釋放
        public final int free() {
            return free(Integer.MAX_VALUE);
        }

        //釋放固定次數
        private int free(int max) {
            int numFreed = 0;
            //釋放固定次數,假設隊列30個元素,如果max=10,那就把隊列中前10個元素釋放掉
            for (; numFreed < max; numFreed++) {
                Entry<T> entry = queue.poll();
                if (entry != null) {
                    freeEntry(entry);
                } else {
                    return numFreed;
                }
            }
            return numFreed;
        }

        //這個方法是用於優化目的,把不常用的緩存釋放掉
        //allocations這個值是一段時間當前緩存被使用的次數
        public final void trim() {
            int free = size - allocations;
            allocations = 0;
            if (free > 0) {
                free(free);
            }
        }

        //真正釋放緩存
        private  void freeEntry(Entry entry) {
            PoolChunk chunk = entry.chunk;
            long handle = entry.handle;

            //entry對象是池化的,回收它。
            entry.recycle();

            //真正釋放,堆內被GC,堆外使用UNSAFE釋放內存空間
            chunk.arena.freeChunk(chunk, handle, sizeClass);
        }

        //Entry 一個池化對象,可以重複利用,內部存儲PoolChunk和handle
        static final class Entry<T> {
            final Handle<Entry<?>> recyclerHandle;
            PoolChunk<T> chunk;
            long handle = -1;

            Entry(Handle<Entry<?>> recyclerHandle) {
                this.recyclerHandle = recyclerHandle;
            }

            void recycle() {
                chunk = null;
                handle = -1;
                recyclerHandle.recycle(this);
            }
        }

        //從池中獲取Entry
        private static Entry newEntry(PoolChunk<?> chunk, long handle) {
            Entry entry = RECYCLER.get();
            entry.chunk = chunk;
            entry.handle = handle;
            return entry;
        }

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章