ByteBuf池化技术Part II

第一部分提到了ByteBuf的内存结构,这儿有几点需要补充并在某些点展开说明

大对象的处理

当申请的分配对象超过Chunk容量大小,Netty就不在使用池化管理的方式了,在每次请求分配内存时单独创建非池化PoolChunk对象进行管理,当对象释放时整个PoolChunk内存释放。

小对象处理

如果申请的内存空间远小于PageSize的话,按照之前提到的,就需要为每个小ByteBuf对象分配一个Page,这就出现内存浪费和内存碎片的问题,Netty将再把Page细分,Netty 将请求的空间大小向上取最近的 16 的倍数(或 2 的幂),规整后小于 PageSize 的小 Buffer 可分为两类。

  • 微型对象:规整后的大小为 16 的整倍数,如 16、32、48、......、496,一共 31 种大小。
  • 小型对象:规整后的大小为 2 的幂,如 512、1024、2048、4096,一共 4 种大小。

这样的话,当向系统申请小对象存储空间时,Netty会先从Poolchunk中申请空闲的Page,同一个Page分为相同大小的buffer,这些Page用PoolSubpage对象进行封装,PoolSubpage内部会记录它自己能分配的小buffer的的规格,可用内存数量,并通过bitmap的方式记录各个小内存的使用情况。虽然这种方案不能完美消灭内存碎片,但是却在很大程度上减少了内存浪费。

基于二叉平衡树的算法结构

上个章节提到Netty中的池化技术实现是基于分层的结构,具体到数据结构的话就是用二叉平衡树进行的实现 当需要创建一个给定大小的ByteBuf,算法需要在PoolChunk中大小为chunkSize的内存中,找到第一个能够容纳申请分配内存的位置

为了方便快速查找chunk中能容纳请求内存的位置,算法构建一个基于byte数组(memoryMap)存储的完全平衡树,该平衡树的多个层级深度,就是前面介绍的按照不同粒度对chunk进行多层分组:

当申请分配大小为chunkSize/2^k的内存,在平衡树高度为k的层级中,从左到右搜索第一个空闲节点

数组的使用域从index = 1开始,将平衡树按照层次顺序依次存储在数组中,depth = n的第1个节点保存在memoryMap[2^n] 中,第2个节点保存在memoryMap[2^n+1]中,以此类推(下图代表已分配chunkSize/2)

可以根据memoryMap[id]的值得出节点的使用情况,memoryMap[id]值越大,剩余的可用内存越少

  • memoryMap[id] = depth_of_id:id节点空闲, 初始状态,depth_of_id的值代表id节点在树中的深度
  • memoryMap[id] = maxOrder + 1:id节点全部已使用,节点内存已完全分配,没有一个子节点空闲
  • depth_of_id < memoryMap[id] < maxOrder + 1:id节点部分已使用 ,memoryMap[id] 的值 x,代表id的子节点中,第一个空闲节点位于深度x,在深度[depth_of_id, x)的范围内没有任何空闲节点 (引用链接:juejin.cn/post/684490...
相关推荐
戮戮5 天前
一次深入排查:Spring Cloud Gateway TCP 连接复用导致 K8s 负载均衡失效
tcp/ip·spring cloud·kubernetes·gateway·负载均衡·netty
fat house cat_5 天前
【netty】基于主从Reactor多线程模型|如何解决粘包拆包问题|零拷贝
java·服务器·网络·netty
Moe4888 天前
Netty技术:SimpleChannelInboundHandler<>的使用
netty
poemyang11 天前
jemalloc思想的极致演绎:深度解构Netty内存池的精妙设计与实现
rpc·netty
poemyang12 天前
“化零为整”的智慧:内存池如何绕过系统调用和GC,构建性能的护城河
rpc·netty
晓牛开发者13 天前
Netty4 TLS单向安全加密传输案例
netty
hanxiaozhang201815 天前
Netty面试重点-2
面试·netty
9527出列16 天前
Netty源码分析--客户端连接接入流程解析
网络协议·netty
马尚来17 天前
【韩顺平】尚硅谷Netty视频教程
后端·netty
马尚道19 天前
【韩顺平】尚硅谷Netty视频教程
netty