转载自: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. 前端进阶必读:《JavaScript核心技术开发解密》核心提炼二

    前言 最近读勒基本关于前端的数据<JavaScript核心技术开发解密>,<webpack从入门到进阶>...这几本书帮助到我更好的理解JS.webpack在前端技术领域中的作 ...

  2. 蓝牙RFCOMM通信

    最近需要在某个开发板上面通过蓝牙和手机蓝牙连接,并通过RFCOMM通信.还没有做过蓝牙RFCOMM相关工作,因此先在linux PC上面调试一下流程,并在此记录调试过程. 一.说明 RFCOMM协议基 ...

  3. 算法-deque双端队列

    Python的deque模块,它是collections库的一部分.deque实现了双端队列,意味着你可以从队列的两端加入和删除元素 1.基本介绍 # 实例化一个deque对象d = deque()d ...

  4. python 多个装饰器的调用顺序分析

    一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器.多个装饰器装饰的顺序是从里到外(就近原则),而调用的顺序是从外到里(就远原则) 样例: def func1(func): ...

  5. Java多线程_ThreadLocal

    用法:ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量. ThreadL ...

  6. 安装Apache所踩的的坑

    刚开始接触PHP等一些脚本语言,需要建立一个本地的服务器,变进行安装了Apache.在其中碰到了诸多问题,和大家一一分享一下. 一.刚解压完成后使用cmd面板进入解压完成的apache的bin目录下, ...

  7. 理解Word2Vec

    一.简介 Word2vec 是 Word Embedding 的方法之一,属于NLP 领域.它是将词转化为「可计算」「结构化」的向量的过程.它是 2013 年由谷歌的 Mikolov 提出了一套新的词 ...

  8. java工具类去掉字符串String中的.点。android开发java程序员常用工具类

    下面是工具类详细代码: package com.qq986945193.david; /** * qq986945193 Project * ============================= ...

  9. [易霖博YCTF]Web WriteUp

    中午队里师傅发到群里的比赛,借来队里师傅账号和队里其他师傅一起做了一下,ak了web,师傅们tql.学到挺多东西,总结一下. rce_nopar 进入题目给出源码: <?php if(isset ...

  10. 【Maven】maven脚本中的maven.test.skip和skipTests的区别

    命令 两种方式跳过编译 test mvn clean install -DskipTests mvn clean install -Dmaven.test.skip=true -DskipTests, ...