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...
相关推荐
西京刀客9 天前
BIO、NIO、AIO的区别?
netty·nio·bio
潇雷13 天前
Netty(3)进阶篇|半包粘包、编解码器
java·后端·netty
WaaTong23 天前
Netty 组件介绍 - ByteBuf
java·开发语言·netty
@阿秋1 个月前
Netty入门基础:IO模型中BIO\NIO概念及区别【附演示代码】
netty
bin的技术小屋1 个月前
谈一谈 Netty 的内存管理 —— 且看 Netty 如何实现 Java 版的 Jemalloc(中)
java·后端·netty
艾特小小1 个月前
基于netty实现简易版rpc服务-理论分析
java·rpc·netty
我神级欧文1 个月前
Netty无锁化设计之对象池实现
java·netty·对象池·无锁化设计
dreamlike_ocean2 个月前
即将到来的Netty4.2版本模型的变化
netty
beiback2 个月前
Springboot + netty + rabbitmq + myBatis
spring boot·mysql·rabbitmq·mybatis·netty·java-rabbitmq
山塘小鱼儿2 个月前
Netty+HTML5+Canvas 网络画画板实时在线画画
java·前端·网络·netty·html5