PooledByteBuf内存池-------这个我现在不太懂
转载自:http://blog.csdn.net/youaremoon/article/details/47910971
http://blog.csdn.net/youaremoon/article/details/47984409
http://blog.csdn.net/youaremoon/article/details/48085591
http://blog.csdn.net/youaremoon/article/details/48184429
http://blog.csdn.net/youaremoon/article/details/50042373
http://blog.csdn.net/youaremoon/article/details/50054387
从netty 4开始,netty加入了内存池管理,采用内存池管理比普通的new ByteBuf性能提高了数十倍。
首先介绍PoolChunk, 该类主要负责内存块的分配与回收,首先来看看两个重要的术语:
page: 可以分配的最小的内存块单位。
chunk: 一堆page的集合。
下面一张图直观的表述了PoolChunk是如何管理内存的:
上图中是一个默认大小的chunk, 由2048个page组成了一个chunk,一个page的大小为8192, chunk之上有11层节点,最后一层节点数与page数量相等。每次内存分配需要保证内存的连续性,这样才能简单的操作分配到的内存,因此这里构造了一颗完整的平衡二叉树,所有子节点的管理的内存也属于其父节点。如果想获取一个8K的内存,则只需在第11层找一个可用节点即可,而如果需要16K的数据,则需要在第10层找一个可用节点,因为需要两个第11层节点。如果一个节点存在一个已经被分配的子节点,则该节点不能被分配,例如需要16K内存,这个时候id=2048的节点已经被分配,id=2049的节点未分配,就不能直接分配1024这个节点,因为这个节点下的内存只有8K了。
通过上面这个树结构,可以看到每次内存分配都是8K*(2^n), 比如需要24K内存时,实际上会申请到一块32K的内存。为了分配一个大小为chunkSize/(2^i)的内存段,需要在深度为i的层从左开始查找可用节点。如想分配16K的内存,chunkSize = 16M( 2048个page * 8K ), 则i=10, 需要从第10层找一个空闲的节点分配内存。
负责内存分配的PoolChunk类,它最小的分配单位为page, 而默认的page size为8K。在实际的应用中,会存在很多小块内存的分配,如果小块内存也占用一个page明显很浪费,针对这种情况,可以将8K的page拆成更小的块,这已经超出chunk的管理范围了,这个时候就出现了PoolSubpage, 其实PoolSubpage做的事情和PoolChunk做的事情类似,只是PoolSubpage管理的是更小的一段内存。
如上图,PoolSubpage将chunk中的一个page再次划分,分成相同大小的N份,这里暂且叫Element,通过对每一个Element的标记与清理标记来进行内存的分配与释放。
介绍了PoolChunk以及针对page的更细粒度的PoolSubpage,其实在chunk的上层还有一个管理类:PoolChunkList,PoolChunkList负责管理多个chunk的生命周期,在此基础上对内存分配进行进一步的优化。
PoolChunkList主要是为了提高内存分配的效率,每个list中包含多个chunk,而多个list又可以形成一个大的link list,在进行内存分配时,先从比较靠前的list中分配内存,这样分配到的几率更大。在高峰期申请过多的内存后,随着流量下降慢慢的释放掉多余内存,形成一个良性的循环。下图是上述三个类的层次结构:
已经讲到了内存池中的几个重要的类:
1、PoolChunk:维护一段连续内存,并负责内存块分配与回收,其中比较重要的两个概念:page:可分配的最小内存块单位;chunk:page的集合;
2、PoolSubpage:将page分为更小的块进行维护;
3、PoolChunkList:维护多个PoolChunk的生命周期。
多个PoolChunkList也会形成一个list,方便内存的管理。最终由PoolArena对这一系列类进行管理,PoolArena本身是一个抽象类,其子类为HeapArena和DirectArena,对应堆内存(heap buffer)和堆外内存(direct buffer),除了操作的内存(byte[]和ByteBuffer)不同外两个类完全一致。
内存池内存分配流程:
1、ByteBufAllocator 准备申请一块内存;
2、尝试从PoolThreadCache中获取可用内存,如果成功则完成此次分配,否则继续往下走,注意后面的内存分配都会加锁;
3、如果是小块(可配置该值)内存分配,则尝试从PoolArena中缓存的PoolSubpage中获取内存,如果成功则完成此次分配;
4、如果是普通大小的内存分配,则从PoolChunkList中查找可用PoolChunk并进行内存分配,如果没有可用的PoolChunk则创建一个并加入到PoolChunkList中,完成此次内存分配;
5、如果是大块(大于一个chunk的大小)内存分配,则直接分配内存而不用内存池的方式;
6、内存使用完成后进行释放,释放的时候首先判断是否和分配的时候是同一个线程,如果是则尝试将其放入PoolThreadCache,这块内存将会在下一次同一个线程申请内存时使用,即前面的步骤2;
7、如果不是同一个线程,则回收至chunk中,此时chunk中的内存使用率会发生变化,可能导致该chunk在不同的PoolChunkList中移动,或者整个chunk回收(chunk在q000上,且其分配的所有内存被释放);同时如果释放的是小块内存(与步骤3中描述的内存相同),会尝试将小块内存前置到PoolArena中,这里操作成功了,步骤3的操作中才可能成功。
在PoolThreadCache中分了tinySubPageHeapCaches、smallSubPageHeapCaches、normalSubPageHeapCaches三个数组,对应于tiny\small\normal在内存分配上的不同(tiny和small使用subpage,normal使用page)。
到此,netty内存池相关介绍已经完,netty就是实现了两个比较经典的分配策略,buddy allocation(见PoolChunk)和jemalloc(有一定改动,PooledByteBufAllocator+PoolArena+PoolChunk+PoolThreadCache),所以如果想了解更新的信息,可以按照上面两个关键词搜索,或则看转载的原文。
netty内存池可调优参数
| 参数名 | 说明 | 默认值 |
| io.netty.allocator.pageSize | page的大小 | 8192 |
| io.netty.allocator.maxOrder | 一个chunk的大小=pageSize << maxOrder | 11 |
| io.netty.allocator.numHeapArenas | heap arena的个数 | min(cpu核数,maxMemory/chunkSize/6),一般来说会=cpu核数 |
| io.netty.allocator.numDirectArenas | direct arena的个数 | min(cpu核数,directMemory/chunkSize/6),一般来说会=cpu核数 |
| io.netty.allocator.tinyCacheSize | PoolThreadCache中tiny cache每个MemoryRegionCache中的Entry个数 | 512 |
| io.netty.allocator.smallCacheSize | PoolThreadCache中small cache每个MemoryRegionCache中的Entry个数 | 256 |
| io.netty.allocator.normalCacheSize | PoolThreadCache中normal cache每个MemoryRegionCache中的Entry个数 | 64 |
| io.netty.allocator.maxCachedBufferCapacity | PoolThreadCache中normal cache数组长度 | 32 * 1024 |
| io.netty.allocator.cacheTrimInterval | PoolThreadCache中的cache收缩阈值,每隔该值次数,会进行一次收缩 | 8192 |
| io.netty.allocator.type | allocator类型,如果不使用内存池,则设置为unpooled | pooled |
| io.netty.noUnsafe | 是否关闭direct buffer | false |
| io.netty.leakDetectionLevel | 内存泄露检测级别 | SIMPLE |
PooledByteBuf内存池-------这个我现在不太懂的更多相关文章
- Netty源码解析 -- 内存池与PoolArena
我们知道,Netty使用直接内存实现Netty零拷贝以提升性能, 但直接内存的创建和释放可能需要涉及系统调用,是比较昂贵的操作,如果每个请求都创建和释放一个直接内存,那性能肯定是不能满足要求的. 这时 ...
- 对象池与.net—从一个内存池实现说起
本来想写篇关于System.Collections.Immutable中提供的ImmutableList里一些实现细节来着,结果一时想不起来源码在哪里--为什么会变成这样呢--第一次有了想写分析的源码 ...
- efficient c++,单线程内存池
基于 http://www.cnblogs.com/diegodu/p/4555018.html operator new的知识基础上 介绍这个章节的内容 对于一般直接 new 与delete 性能较 ...
- 感悟优化——Netty对JDK缓冲区的内存池零拷贝改造
NIO中缓冲区是数据传输的基础,JDK通过ByteBuffer实现,Netty框架中并未采用JDK原生的ByteBuffer,而是构造了ByteBuf. ByteBuf对ByteBuffer做了大量的 ...
- linux内存源码分析 - 内存池
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 内存池是用于预先申请一些内存用于备用,当系统内存不足无法从伙伴系统和slab中获取内存时,会从内存池中获取预留的 ...
- loki之内存池SmallObj[原创]
loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板 ...
- 内存池-转载自IBM
[转载自IBM]讲的很好~推荐看看 6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的 ...
- 常见C++内存池技术
原文:http://www.cppblog.com/weiym/archive/2013/04/08/199238.html 总结下常见的C++内存池,以备以后查询.应该说没有一个内存池适合所有的情况 ...
- Boost内存池使用与测试
目录 Boost内存池使用与测试 什么是内存池 内存池的应用场景 安装 内存池的特征 无内存泄露 申请的内存数组没有被填充 任何数组内存块的位置都和使用operator new[]分配的内存块位置一致 ...
随机推荐
- 初学Linux (Linux_note)
根目录:/ /root: 存放root用户相关文件 /home: 存放不同用户的相关文件 /bin: 存放常用命令的目录 /sbin: 要具有一定权限才可以使用的命令 /mnt: 默认挂载光驱和软驱的 ...
- install-newton部署安装--------控制节点
#################################################################################################### ...
- 如何加速github下载速度
第一步 魔法 第二步 git config --global http.proxy http://127.0.0.1:1080 git config --global https.proxy http ...
- A distributional code for value in dopamine-based reinforcement learning
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Nature 2020 汇报PPT: 链接:https://pan.baidu.com/s/1RWx6miX6iZUNgNfV9B69FQ ...
- soso官方:基于相关排序的判断
http://www.wocaoseo.com/thread-186-1-1.html 议程 概述 检索词 用户的信息需求 网页的自有信息 网页的附属信息 相关性的计算框架 概述 相关性的表象 检索词 ...
- PyTorch入门-CIFAR10图像分类
CIFAR10数据集下载 CIFAR10数据集包含10个类别,图像尺寸为 3×32×32 官方下载地址很慢,这里给一个百度云: https://pan.baidu.com/s/1oTvW8wNa-VO ...
- 招新裁老,两面派互联网大厂,培训三个月,就拿15K,凭什么?
看到一位朋友在发帖子求问:亲身经历,(如有谎言我名字倒过来写)一个大学同学18年毕业的.在兰州一个二本学的兽医农牧,毕业难找工作,去深圳一个机构培训了三个月吧,然后就去做大数据 算法了,然后又去做ja ...
- vmware虚拟机Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)详解
原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 我怕链 ...
- 关于js重名方法的先后调用问题
当js中方法重名时,最后引入的js会覆盖前面的引入的js(就是说会调用最后引入的js中的方法)详情参照(main.js与white.js 的a())但是,当最后一个js中存在语法上的错误时(也可以是本 ...
- Java反射(一)
什么是反射? 在程序的运行过程中,可以动态的创建对象. 反射的基石是什么? 字节码对象是反射的基石.字节码对象:Java类文件通过javac进行编译后生成的xxx.class文件,此文件由jvm加载至 ...