转载自: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内存池-------这个我现在不太懂的更多相关文章

  1. Netty源码解析 -- 内存池与PoolArena

    我们知道,Netty使用直接内存实现Netty零拷贝以提升性能, 但直接内存的创建和释放可能需要涉及系统调用,是比较昂贵的操作,如果每个请求都创建和释放一个直接内存,那性能肯定是不能满足要求的. 这时 ...

  2. 对象池与.net—从一个内存池实现说起

    本来想写篇关于System.Collections.Immutable中提供的ImmutableList里一些实现细节来着,结果一时想不起来源码在哪里--为什么会变成这样呢--第一次有了想写分析的源码 ...

  3. efficient c++,单线程内存池

    基于 http://www.cnblogs.com/diegodu/p/4555018.html operator new的知识基础上 介绍这个章节的内容 对于一般直接 new 与delete 性能较 ...

  4. 感悟优化——Netty对JDK缓冲区的内存池零拷贝改造

    NIO中缓冲区是数据传输的基础,JDK通过ByteBuffer实现,Netty框架中并未采用JDK原生的ByteBuffer,而是构造了ByteBuf. ByteBuf对ByteBuffer做了大量的 ...

  5. linux内存源码分析 - 内存池

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 内存池是用于预先申请一些内存用于备用,当系统内存不足无法从伙伴系统和slab中获取内存时,会从内存池中获取预留的 ...

  6. loki之内存池SmallObj[原创]

    loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板 ...

  7. 内存池-转载自IBM

    [转载自IBM]讲的很好~推荐看看 6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的 ...

  8. 常见C++内存池技术

    原文:http://www.cppblog.com/weiym/archive/2013/04/08/199238.html 总结下常见的C++内存池,以备以后查询.应该说没有一个内存池适合所有的情况 ...

  9. Boost内存池使用与测试

    目录 Boost内存池使用与测试 什么是内存池 内存池的应用场景 安装 内存池的特征 无内存泄露 申请的内存数组没有被填充 任何数组内存块的位置都和使用operator new[]分配的内存块位置一致 ...

随机推荐

  1. 28个漂亮的React.js后台管理模板

    React管理模板 为您的React Web应用程序开发一个管理区域可能非常耗时.它与设计所有前端页面一样重要. 这是2020年设计出色的顶级React.js后台管理模板的列表. 这些模板确实有价值, ...

  2. 使用 codeblocks 编写C++ udp组播程序遇到的问题

    编译错误 会出现好多undefined reference to'WSAStartup to@8之类的错误,都是undefind开头的 解决方法: Settings -> Compiler se ...

  3. java泛型笔记

    目录 概述 什么是泛型?为什么使用泛型? 例子 特性 使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法的基本用法 泛型方法与可变参数 静态方法与泛型 泛型 ...

  4. 记录一下前端性能优化-为何操作DOM会变慢?

    对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩(css.js.图片皆可压缩) 样式表放头部,脚本放底部 使用CDN(这部分, ...

  5. java基础-02:编译型和解释型

    Java程序运行机制: Java语言的编译-->解释-->运行过程 1.编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的 ...

  6. Golang中使用set

    两种 go 实现 set 的思路, 分别是 map 和 bitset. map 的 key 肯定是唯一的,而这恰好与 set 的特性一致,天然保证 set 中成员的唯一性.而且通过 map 实现 se ...

  7. nova 数据库中删除虚机

    Database changed MariaDB [nova]> SET FOREIGN_KEY_CHECKS=; Query OK, rows affected (0.000 sec) Mar ...

  8. vmware 虚拟机共享 windows 目录

    1.vmware 配置: 2.虚拟机进行配置: 虚拟机安装vmware-tools 3.虚拟机中挂载sr0(cdrom): [root@bogon ~]# mount /dev/sr0 /mnt/ m ...

  9. xfs文件系统修复方法

    1. 前言首先尝试mount和umount文件系统,以便重放日志,修复文件系统,如果不行,再进行如下操作.fdisk -l 查看硬盘分区情况mount -l 查看文件系统挂载情况df -h 查看文件系 ...

  10. pandas 数据子集的获取

    有时数据读入后并不是对整体数据进行分析,而是数据中的部分子集,例如,对于地铁乘客量可能只关心某些时间段的流量,对于商品的交易可能只需要分析某些颜色的价格变动,对于医疗诊断数据可能只对某个年龄段的人群感 ...