// Metrics for allocations and deallocations /** * 分配 Normal 内存块的次数 */ privatelong allocationsNormal; // We need to use the LongCounter here as this is not guarded via synchronized block. /** * 分配 Tiny 内存块的次数 */ privatefinal LongCounter allocationsTiny = PlatformDependent.newLongCounter(); /** * 分配 Small 内存块的次数 */ privatefinal LongCounter allocationsSmall = PlatformDependent.newLongCounter(); /** * 分配 Huge 内存块的次数 */ privatefinal LongCounter allocationsHuge = PlatformDependent.newLongCounter(); /** * 正在使用中的 Huge 内存块的总共占用字节数 */ privatefinal LongCounter activeBytesHuge = PlatformDependent.newLongCounter();
/** * 释放 Huge 内存块的次数 */ // We need to use the LongCounter here as this is not guarded via synchronized block. privatefinal LongCounter deallocationsHuge = PlatformDependent.newLongCounter();
/** * 该 PoolArena 被多少线程引用的计数器 */ // Number of thread caches backed by this arena. final AtomicInteger numThreadCaches = new AtomicInteger();
第 26 至 31 行:容量变大,说明是扩容,调用 #memoryCopy(T src, int srcOffset, T dst, int dstOffset, int length)抽象方法,将老的内存块的数据( 此处的复制,是全部数据 ),复制到新的内存块中。需要 PoolArea 子类实现该方法,代码如下:
protectedabstractvoidmemoryCopy(T src, int srcOffset, T dst, int dstOffset, int length);
第 33 至 48 行:容量变小,说明是缩容。
第 34 至 44 行:有部分数据未读取完,调用 #memoryCopy(T src, int srcOffset, T dst, int dstOffset, int length)抽象方法,将老的内存块的数据( 此处的复制,是全部数据 ),复制到新的内存块中。😈 注意,此处复制的只有未读取完的部分数据。
/** * Returns the number of thread caches backed by this arena. */ intnumThreadCaches();
/** * Returns the number of tiny sub-pages for the arena. */ intnumTinySubpages(); /** * Returns the number of small sub-pages for the arena. */ intnumSmallSubpages(); /** * Returns the number of chunk lists for the arena. */ intnumChunkLists();
/** * Returns an unmodifiable {@link List} which holds {@link PoolSubpageMetric}s for tiny sub-pages. */ List<PoolSubpageMetric> tinySubpages(); /** * Returns an unmodifiable {@link List} which holds {@link PoolSubpageMetric}s for small sub-pages. */ List<PoolSubpageMetric> smallSubpages(); /** * Returns an unmodifiable {@link List} which holds {@link PoolChunkListMetric}s. */ List<PoolChunkListMetric> chunkLists();
/** * Return the number of allocations done via the arena. This includes all sizes. */ longnumAllocations(); /** * Return the number of tiny allocations done via the arena. */ longnumTinyAllocations(); /** * Return the number of small allocations done via the arena. */ longnumSmallAllocations(); /** * Return the number of normal allocations done via the arena. */ longnumNormalAllocations(); /** * Return the number of huge allocations done via the arena. */ longnumHugeAllocations();
/** * Return the number of deallocations done via the arena. This includes all sizes. */ longnumDeallocations(); /** * Return the number of tiny deallocations done via the arena. */ longnumTinyDeallocations(); /** * Return the number of small deallocations done via the arena. */ longnumSmallDeallocations(); /** * Return the number of normal deallocations done via the arena. */ longnumNormalDeallocations(); /** * Return the number of huge deallocations done via the arena. */ longnumHugeDeallocations();
/** * Return the number of currently active allocations. */ longnumActiveAllocations();
/** * Return the number of currently active tiny allocations. */ longnumActiveTinyAllocations(); /** * Return the number of currently active small allocations. */ longnumActiveSmallAllocations(); /** * Return the number of currently active normal allocations. */ longnumActiveNormalAllocations(); /** * Return the number of currently active huge allocations. */ longnumActiveHugeAllocations();
/** * Return the number of active bytes that are currently allocated by the arena. */ longnumActiveBytes(); }
@Override public List<PoolSubpageMetric> tinySubpages(){ return subPageMetricList(tinySubpagePools); }
@Override public List<PoolSubpageMetric> smallSubpages(){ return subPageMetricList(smallSubpagePools); }
@Override public List<PoolChunkListMetric> chunkLists(){ return chunkListMetrics; }
privatestatic List<PoolSubpageMetric> subPageMetricList(PoolSubpage<?>[] pages){ List<PoolSubpageMetric> metrics = new ArrayList<PoolSubpageMetric>(); for (PoolSubpage<?> head : pages) { if (head.next == head) { continue; } PoolSubpage<?> s = head.next; for (;;) { metrics.add(s); s = s.next; if (s == head) { break; } } } return metrics; }
@Override publiclongnumActiveBytes(){ long val = activeBytesHuge.value(); synchronized (this) { for (int i = 0; i < chunkListMetrics.size(); i++) { for (PoolChunkMetric m: chunkListMetrics.get(i)) { val += m.chunkSize(); } } } return max(0, val); }
protectedabstractvoidmemoryCopy(T src, int srcOffset, T dst, int dstOffset, int length); // protectedabstractvoiddestroyChunk(PoolChunk<T> chunk);
3. HeapArena
HeapArena ,继承 PoolArena 抽象类,对 Heap 类型的内存分配。
HeapArena 是 PoolArena 的内部静态类。代码比较简单,胖友自己看看就成。
static final class HeapArena extends PoolArena<byte[]> { // 管理 byte[] 数组
HeapArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize, int directMemoryCacheAlignment) { super(parent, pageSize, maxOrder, pageShifts, chunkSize, directMemoryCacheAlignment); }
staticfinalclassDirectArenaextendsPoolArena<ByteBuffer> { // 管理 Direct ByteBuffer 对象
DirectArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize, int directMemoryCacheAlignment) { super(parent, pageSize, maxOrder, pageShifts, chunkSize, directMemoryCacheAlignment); }
@Override booleanisDirect(){ returntrue; }
privateintoffsetCacheLine(ByteBuffer memory){ // We can only calculate the offset if Unsafe is present as otherwise directBufferAddress(...) will // throw an NPE. return HAS_UNSAFE ? (int) (PlatformDependent.directBufferAddress(memory) & directMemoryCacheAlignmentMask) : 0; }
@Override protected PoolChunk<ByteBuffer> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize){ if (directMemoryCacheAlignment == 0) { returnnew PoolChunk<ByteBuffer>(this, allocateDirect(chunkSize), pageSize, maxOrder, pageShifts, chunkSize, 0); } final ByteBuffer memory = allocateDirect(chunkSize + directMemoryCacheAlignment); returnnew PoolChunk<ByteBuffer>(this, memory, pageSize, maxOrder, pageShifts, chunkSize, offsetCacheLine(memory)); }
@Override protectedvoidmemoryCopy(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int length){ if (length == 0) { return; }
if (HAS_UNSAFE) { PlatformDependent.copyMemory( PlatformDependent.directBufferAddress(src) + srcOffset, PlatformDependent.directBufferAddress(dst) + dstOffset, length); } else { // We must duplicate the NIO buffers because they may be accessed by other Netty buffers. src = src.duplicate(); dst = dst.duplicate(); src.position(srcOffset).limit(srcOffset + length); dst.position(dstOffset); dst.put(src); } } }