java构建内存池队列_Netty内存池之PoolThreadCache详解

本文详细解析了Netty内存管理中的PoolThreadCache,每个线程都有一个PoolThreadCache,它维护了tiny、small和normal类型的内存缓存。在内存申请时,首先从缓存中获取,满时释放回公共内存池。PoolThreadCache的数据结构包括三个数组,每个数组对应不同大小的内存块,使用MemoryRegionCache和Entry存储。在内存释放时,如果队列未满则存入PoolThreadCache,满则释放回PoolArena。初始化时,PoolThreadCache与PoolThreadLocalCache绑定,使用最少被占用的PoolArena。内存申请时,从缓存中分配内存块,达到一定次数后进行内存修剪。
摘要由CSDN通过智能技术生成

PoolThreadCahche是Netty内存管理中能够实现高效内存申请和释放的一个重要原因,Netty会为每一个线程都维护一个PoolThreadCache对象,当进行内存申请时,首先会尝试从PoolThreadCache中申请,如果无法从中申请到,则会尝试从Netty的公共内存池中申请。本文首先会对PoolThreadCache的数据结构进行讲解,然后会介绍Netty是如何初始化PoolThreadCache的,最后会介绍如何在PoolThreadCache中申请内存和如何将内存释放到PoolThreadCache中。

1. PoolThreadCache数据结构

PoolThreadCache的数据结构与PoolArena的主要属性结构非常相似,但细微位置有很大的不同。在PoolThreadCache中,其维护了三个数组(我们以直接内存的缓存方式为例进行讲解),如下所示:

// 存储tiny类型的内存缓存,该数组长度为32,其中只有下标为1~31的元素缓存了有效数据,第0号位空置。

// 这里内存大小的存储方式也与PoolSubpage类似,数组的每一号元素都存储了不同等级的内存块,每个等级的

// 内存块的内存大小差值为16byte,比如第1号位维护了大小为16byte的内存块,第二号为维护了大小为32byte的

// 内存块,依次类推,第31号位维护了大小为496byte的内存块。

private final MemoryRegionCache[] tinySubPageDirectCaches;

// 存储small类型的内存缓存,该数组长度为4,数组中每个元素中维护的内存块大小也是成等级递增的,并且这里

// 的递增方式是按照2的指数次幂进行的,比如第0号为维护的是大小为512byte的内存块,第1号位维护的是大小为

// 1024byte的内存块,第2号位维护的是大小为2048byte的内存块,第3号位维护的是大小为4096byte的内存块

private final MemoryRegionCache[] smallSubPageDirectCaches;

// 存储normal类型的内存缓存。需要注意的是,这里虽说是维护的normal类型的缓存,但是其只维护2<<13,2<<14

// 和2<<15三个大小的内存块,而该数组的大小也正好为3,因而这三个大小的内存块将被依次放置在该数组中。

// 如果申请的目标内存大于2<<15,那么Netty会将申请动作交由PoolArena进行。

private final MemoryRegionCache[] normalDirectCaches;

这三个数组分别保存了tiny,small和normal类型的缓存数据,不同于PoolArena的使用PoolSubpage和PoolChunk进行内存的维护,这里都是使用MemoryRegionCache进行的。另外,在MemoryRegionCache中保存了一个有界队列,对于tiny类型的缓存,该队列的长度为512,对于small类型的缓存,该队列的长度为256,对于normal类型的缓存,该队列的长度为64。在进行内存释放的时候,如果队列已经满了,那么就会将该内存块释放回PoolArena中。这里需要说明的是,这里的队列中的元素统一使用的是Entry这种数据结构,该结构的主要属性如下:

static final class Entry {

// 用于循环利用当前Entry对象的处理器,该处理器的实现原理,我们后续将进行讲解

final Handle> recyclerHandle;

// 记录了当前内存块是从哪一个PoolChunk中申请得来的

PoolChunk chunk;

// 如果是直接内存,该属性记录了当前内存块所在的ByteBuffer对象

ByteBuffer nioBuffer;

// 由于当前申请的内存块在PoolChunk以及PoolSubpage中的位置是可以通过一个长整型参数来表示的,

// 这个长整型参数就是这里的handle,因而这里直接将其记录下来,以便后续需要将当前内存块释放到

// PoolArena中时,能够快速获取其所在的位置

long handle = -1;

}

PoolThreadCache中维护每一个内存块最终都是使用的一个Entry对象来进行的,从上面的属性可以看出,记录该内存块最重要的属性是chunk和handle,chunk记录了当前内存块所在的PoolChunk对象,而handle则记录了当前内存块是在PoolChunk和PoolSubpage中的哪个位置(关于PoolChunk,PoolSubpage和PoolArena的实现原理,建议读者阅读一下前面的文章,这样有助于读者快速理解相关原理)。如此,对于Netty使用的PoolThreadCache的存储结构我们就有了一个比较清晰的认识。下面我们通过一幅图来对PoolThreadCache的数据结构进行一个整体的演示:</

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值