该文所涉及的 netty 源码版本为 4.1.16。

Netty 内存池申请内存流程

在通过 PooledByteBufAllocator 中向内存池中进行内存申请的时候,最先开始的步骤便是从 PooledByteBufAllocator 中一系列 PoolArena 数组中,选择其中一个 PoolArena 进行分配。

这时将会从 PoolArena 数组中选取当前使用量最小的 PoolArena 与当前线程通过 ThreadLocal 进行绑定,之后涉及到内存申请将会直接从这个 PoolArena 进行获取,这个做法在高并发情况下频繁往内存池中进行内存申请的时候可以减少资源竞争,提升效率。

在当前线程获取与其绑定的 PoolArena 之后,接下来就是从 PoolArena 中继续申请内存。
为了适应各种大小的内存场景,PoolArena 的组成也是为了其设计。

  • PoolSubpage 数组 tinySubpagePools:默认情况下,当申请的内存小于 512b 的时候的时候将会从 tinySubpagePools 中直接选择 subPage(内存池中的最小单位)返回
  • PoolSubpage 数组 smallSubpagePools:默认情况下,当申请的内存大于 512b 但是小于一个 page 的大小(8kb)的时候,将会从 smallSubpagePools 返回一个 subPage。subPage 是由 poolChunk 中的 page 分配而来。
  • PoolChunkList qInit:存储内存利用率 0-25%的 poolChunk
  • PoolChunkList q000:存储内存利用率 1-50%的 poolChunk
  • PoolChunkList q025:存储内存利用率 25-75%的 poolChunk
  • PoolChunkList q050:存储内存利用率 50-100%的 poolChunk
  • PoolChunkList q075:存储内存利用率 75-100%的 poolChunk
  • PoolChunkList q100:存储内存利用率 100%的 poolChunk、 当申请的内存大于一个 page(8kb)但又小于一个 poolChunk(2048kb)总大小的时候,将会从各个 PoolChunkList 中尝试获取一个 poolChunk 从中返回。PoolChunkList 是一个由 poolChunk 组成的链表。
    以上几个 PoolChunkList,由符合各个内存利用率的 poolChunk 组成,这几个 PoolChunkList 之间又互相首尾连接组成队列,方便 PoolChunk 在各个队列中根据自己当前的利用率进行转移到对应的位置上。
    最后,当申请的内存大于一个 poolChunk 大小的时候将会直接申请一段非池化的内存返回,并不会占用内存池中的内存空间。

最后,到了从 poolChunk 中申请内存的场景,这一部分在该文中已经详细说明,这部分也是内存池中获取内存的最后一步。