Netty源码解析 -- 内存池与PoolArena

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们知道,Netty使用直接内存实现Netty零拷贝以提升性能,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但直接内存的创建和释放可能需要涉及系统调用,是比较昂贵的操作,如果每个请求都创建和释放一个直接内存,那性能肯定是不能满足要求的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这时就需要使用内存池。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"即从系统中申请一大块内存,再在上面分配每个请求所需的内存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Netty中的内存池主要涉及PoolArena,PoolChunk与PoolSubpage。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要分析PoolArena的作用与实现。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"源码分析基于Netty 4.1.52"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"接口关系"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ByteBufAllocator,内存分配器,负责为ByteBuf分配内存, 线程安全。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PooledByteBufAllocator,池化内存分配器,默认的ByteBufAllocator,预先从操作系统中申请一大块内存,在该内存上分配内存给ByteBuf,可以提高性能和减小内存碎片。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"UnPooledByteBufAllocator,非池化内存分配器,每次都从操作系统中申请内存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RecvByteBufAllocator,接收内存分配器,为Channel读入的IO数据分配一块大小合理的buffer空间。具体功能交由内部接口Handle定义。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它主要是针对Channel读入场景添加一些操作,如guess,incMessagesRead,lastBytesRead等等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ByteBuf,分配好的内存块,可以直接使用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面只关注PooledByteBufAllocator,它是Netty中默认的内存分配器,也是理解Netty内存机制的难点。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"内存分配"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面文章《ChannelPipeline机制与读写过程》中分析了数据读取过程,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NioByteUnsafe#read"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"public final void read() {\n ...\n final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();\n allocHandle.reset(config);\n\n ByteBuf byteBuf = null;\n\n ...\n byteBuf = allocHandle.allocate(allocator);\n allocHandle.lastBytesRead(doReadBytes(byteBuf));\n ...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"recvBufAllocHandle方法返回AdaptiveRecvByteBufAllocator.HandleImpl。(AdaptiveRecvByteBufAllocator,PooledByteBufAllocator都在DefaultChannelConfig中初始化)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AdaptiveRecvByteBufAllocator.HandleImpl#allocate -> AbstractByteBufAllocator#ioBuffer -> PooledByteBufAllocator#directBuffer -> PooledByteBufAllocator#newDirectBuffer"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {\n // #1\n PoolThreadCache cache = threadCache.get();\n PoolArena directArena = cache.directArena;\n\n final ByteBuf buf;\n if (directArena != null) {\n // #2\n buf = directArena.allocate(cache, initialCapacity, maxCapacity);\n } else {\n // #3\n buf = PlatformDependent.hasUnsafe() ? UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) : new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);\n }\n return toLeakAwareBuffer(buf);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AbstractByteBufAllocator#ioBuffer方法会判断当前系统是否支持unsafe。支持时使用直接内存,不支持则使用堆内存。这里只关注直接内存的实现。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" 从当前线程缓存中获取对应内存池PoolArena"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#2"}]},{"type":"text","text":" 在当前线程内存池上分配内存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#3"}]},{"type":"text","text":" 内存池不存在,只能使用非池化内存分配内存了"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PooledByteBufAllocator#threadCache是一个PoolThreadLocalCache实例,PoolThreadLocalCache继承于FastThreadLocal,FastThreadLocal这里简单理解为对ThreadLocal的优化,它为每个线程维护了一个PoolThreadCache,PoolThreadCache上关联了内存池。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当PoolThreadLocalCache上某个线程的PoolThreadCache不存在时,通过initialValue方法构造。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolThreadLocalCache#initialValue"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"protected synchronized PoolThreadCache initialValue() {\n // #1\n final PoolArena heapArena = leastUsedArena(heapArenas);\n final PoolArena directArena = leastUsedArena(directArenas);\n // #2\n final Thread current = Thread.currentThread();\n if (useCacheForAllThreads || current instanceof FastThreadLocalThread) {\n final PoolThreadCache cache = new PoolThreadCache(\n heapArena, directArena, smallCacheSize, normalCacheSize,\n DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);\n\n ...\n }\n // No caching so just use 0 as sizes.\n return new PoolThreadCache(heapArena, directArena, 0, 0, 0, 0);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" 从PooledByteBufAllocator的heapArenas,directArenas中获取使用率最小的PoolArena。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PooledByteBufAllocator构造时默认会为PooledByteBufAllocator#directArenas初始化8个PoolArena。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#2"}]},{"type":"text","text":" 构造PoolThreadCache。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolArena,可以理解为一个内存池,负责管理从操作系统中申请到的内存块。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolThreadCache为每一个线程关联一个PoolArena(PoolThreadCache#directArena),该线程的内存都在该PoolArena上分配。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Netty支持高并发系统,可能有很多线程进行同时内存分配。为了缓解线程竞争,通过创建多个PoolArena细化锁的粒度,从而提高并发执行的效率。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意,一个PoolArena可以会分给多个的线程,可以看到PoolArena上会有一些同步操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"内存级别"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面分析SizeClasses的文章说过,Netty将内存池中的内存块按大小划分为3个级别。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同级别的内存块管理算法不同。默认划分规则如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"small <= 28672(3.5K)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"normal <= 16777216(2M)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"huge > 16777216(2M)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"smallSubpagePools是一个PoolSubpage数组,负责维护small级别的内存块信息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolChunk负责维护normal级别的内存,PoolChunkList管理一组PoolChunk。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolArena按内存使用率将PoolChunk分别维护到6个PoolChunkList中,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolArena按内存使用率将PoolChunk分别维护到6个PoolChunkList中,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"qInit->内存使用率为0~25,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"q000->内存使用率为1~50,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"q025->内存使用率为25~75,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"q050->内存使用率为50~75,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"q075->内存使用率为75~100,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"q100->内存使用率为100。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:PoolChunk是Netty每次向操作系统申请的内存块。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolSubpage需要从PoolChunk中分配,而Tiny,Small级别的内存则是从PoolSubpage中分配。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面来看一下分配过程"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"private void allocate(PoolThreadCache cache, PooledByteBuf buf, final int reqCapacity) {\n // #1\n final int sizeIdx = size2SizeIdx(reqCapacity);\n // #2\n if (sizeIdx <= smallMaxSizeIdx) {\n tcacheAllocateSmall(cache, buf, reqCapacity, sizeIdx);\n } else if (sizeIdx < nSizes) {\n // #3\n tcacheAllocateNormal(cache, buf, reqCapacity, sizeIdx);\n } else {\n // #4\n int normCapacity = directMemoryCacheAlignment > 0\n ? normalizeSize(reqCapacity) : reqCapacity;\n // Huge allocations are never served via the cache so just call allocateHuge\n allocateHuge(buf, normCapacity);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" size2SizeIdx是父类SizeClasses提供的方法,它使用特定算法,将申请的内存大小调整为规范大小,划分到对应位置,返回对应索引,可参考《内存对齐类SizeClasses》"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#2"}]},{"type":"text","text":" 分配small级别的内存块"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#3"}]},{"type":"text","text":" 分配normal级别的内存块"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#4"}]},{"type":"text","text":" 分配huge级别的内存块"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"private void tcacheAllocateSmall(PoolThreadCache cache, PooledByteBuf buf, final int reqCapacity,\n final int sizeIdx) {\n // #1\n if (cache.allocateSmall(this, buf, reqCapacity, sizeIdx)) {\n return;\n }\n\n // #2\n final PoolSubpage head = smallSubpagePools[sizeIdx];\n final boolean needsNormalAllocation;\n synchronized (head) {\n // #3\n final PoolSubpage s = head.next;\n needsNormalAllocation = s == head;\n if (!needsNormalAllocation) {\n assert s.doNotDestroy && s.elemSize == sizeIdx2size(sizeIdx);\n long handle = s.allocate();\n assert handle >= 0;\n s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity, cache);\n }\n }\n // #4\n if (needsNormalAllocation) {\n synchronized (this) {\n allocateNormal(buf, reqCapacity, sizeIdx, cache);\n }\n }\n\n incSmallAllocation();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" 首先尝试在线程缓存上分配。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了PoolArena,PoolThreadCache#smallSubPageHeapCaches还为每个线程维护了Small级别的内存缓存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#2"}]},{"type":"text","text":" 使用前面SizeClasses#size2SizeIdx方法计算的索引,获取对应PoolSubpage"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#3"}]},{"type":"text","text":" 注意,head是一个占位节点,并不存储数据,s==head表示当前存在可以用的PoolSubpage,因为已经耗尽的PoolSubpage是会从链表中移除。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着从PoolSubpage中分配内存,后面有文章解析详细过程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意,这里必要运行在同步机制中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#4"}]},{"type":"text","text":" 没有可用的PoolSubpage,需要申请一个Normal级别的内存块,再在上面分配所需内存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"normal级别的内存也是先尝试在线程缓存中分配,分配失败后再调用allocateNormal方法申请"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolArena#allocate -> allocateNormal"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"private void allocateNormal(PooledByteBuf buf, int reqCapacity, int sizeIdx, PoolThreadCache threadCache) {\n if (q050.allocate(buf, reqCapacity, sizeIdx, threadCache) ||\n q025.allocate(buf, reqCapacity, sizeIdx, threadCache) ||\n q000.allocate(buf, reqCapacity, sizeIdx, threadCache) ||\n qInit.allocate(buf, reqCapacity, sizeIdx, threadCache) ||\n q075.allocate(buf, reqCapacity, sizeIdx, threadCache)) {\n return;\n }\n\n // Add a new chunk.\n PoolChunk c = newChunk(pageSize, nPSizes, pageShifts, chunkSize);\n boolean success = c.allocate(buf, reqCapacity, sizeIdx, threadCache);\n assert success;\n qInit.add(c);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" 依次从q050,q025,q000,qInit,q075上申请内存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为什么要是这个顺序呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolArena中的PoolChunkList之间也组成一个“双向”链表"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"qInit ---> q000 q025 q050 q075 q100"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolChunkList中还维护了minUsage,maxUsage,即当一个PoolChunk使用率大于maxUsage,它将被移动到下一个PoolChunkList,使用率小于minUsage,则被移动到前一个PoolChunkList。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:q000没有前置节点,它的minUsage为1,即上面的PoolChunk内存完全释放后,将被销毁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"qInit的前置节点是它自己,但它的minUsage为Integer.MIN_VALUE,即使上面的PoolChunk内存完全释放后,也不会被销毁,而是继续保留在内存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不优先从q000分配,正是因为q000上的PoolChunk内存完全释放后要被销毁,如果在上面分配,则会延迟内存的回收进度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而q075上由于内存利用率太高,导致内存分配的成功率大大降低,因此放到最后。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以从q050是一个不错的选择,这样大部分情况下,Chunk的利用率都会保持在一个较高水平,提高整个应用的内存利用率;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在PoolChunkList上申请内存,PoolChunkList会遍历链表上PoolChunk节点,直到分配成功或到达链表末尾。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolChunk分配后,如果内存使用率高于maxUsage,它将被移动到下一个PoolChunkList。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"newChunk方法负责构造一个PoolChunk,这里是内存池向操作系统申请内存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DirectArena#newChunk"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"protected PoolChunk newChunk(int pageSize, int maxPageIdx,\n int pageShifts, int chunkSize) {\n if (directMemoryCacheAlignment == 0) {\n return new PoolChunk(this,\n allocateDirect(chunkSize), pageSize, pageShifts,\n chunkSize, maxPageIdx, 0);\n }\n final ByteBuffer memory = allocateDirect(chunkSize\n + directMemoryCacheAlignment);\n return new PoolChunk(this, memory, pageSize,\n pageShifts, chunkSize, maxPageIdx,\n offsetCacheLine(memory));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"allocateDirect方法向操作系统申请内存,获得一个(jvm)ByteBuffer,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PoolChunk#memory维护了该ByteBuffer,PoolChunk的内存实际上都是在该ByteBuffer上分配。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后是huge级别的内存申请"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"private void allocateHuge(PooledByteBuf buf, int reqCapacity) {\n PoolChunk chunk = newUnpooledChunk(reqCapacity);\n activeBytesHuge.add(chunk.chunkSize());\n buf.initUnpooled(chunk, reqCapacity);\n allocationsHuge.increment();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比较简单,没有使用内存池,直接向操作系统申请内存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"内存释放"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"void free(PoolChunk chunk, ByteBuffer nioBuffer, long handle, int normCapacity, PoolThreadCache cache) {\n if (chunk.unpooled) {\n // #1\n int size = chunk.chunkSize();\n destroyChunk(chunk);\n activeBytesHuge.add(-size);\n deallocationsHuge.increment();\n } else {\n // #2\n SizeClass sizeClass = sizeClass(handle);\n if (cache != null && cache.add(this, chunk, nioBuffer, handle, normCapacity, sizeClass)) {\n // cached so not free it.\n return;\n }\n\n freeChunk(chunk, handle, normCapacity, sizeClass, nioBuffer, false);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#1"}]},{"type":"text","text":" 非池化内存,直接销毁内存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"#2"}]},{"type":"text","text":" 池化内存,首先尝试加到线程缓存中,成功则不需要其他操作。失败则调用freeChunk"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"void freeChunk(PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass, ByteBuffer nioBuffer,\n boolean finalizer) {\n final boolean destroyChunk;\n synchronized (this) {\n ...\n destroyChunk = !chunk.parent.free(chunk, handle, normCapacity, nioBuffer);\n }\n if (destroyChunk) {\n // destroyChunk not need to be called while holding the synchronized lock.\n destroyChunk(chunk);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"chunk.parent即PoolChunkList,PoolChunkList#free会调用PoolChunk释放内存,释放内存后,如果内存使用率低于minUsage,则移动前一个PoolChunkList,如果前一个PoolChunkList不存在(q000),则返回false,由后面的步骤销毁该PoolChunk。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可回顾前面解析ByteBuf文章中关于内存销毁的内容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/da/da6c5c8363dc2a6fc148bc2eab39d883.jpeg","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章