Netty源码解析 -- 内存对齐类SizeClasses
在学习Netty内存池之前,我们先了解一下Netty的内存对齐类SizeClasses,它为Netty内存池中的内存块提供大小对齐,索引计算等服务方法。
源码分析基于Netty 4.1.52
Netty内存池中每个内存块size都符合如下计算公式
size = 1 << log2Group + nDelta * (1 << log2Delta)
log2Group:内存块分组
nDelta:增量乘数
log2Delta:增量大小的log2值
SizeClasses初始化后,将计算chunkSize(内存池每次向操作系统申请内存块大小)范围内每个size的值,保存到sizeClasses字段中。
sizeClasses是一个表格(二维数组),共有7列,含义如下
index:内存块size的索引
log2Group:内存块分组,用于计算对应的size
log2Delata:增量大小的log2值,用于计算对应的size
nDelta:增量乘数,用于计算对应的size
isMultipageSize:表示size是否为page的倍数
isSubPage:表示是否为一个subPage类型
log2DeltaLookup:如果size存在位图中的,记录其log2Delta,未使用
sizeClasses负责计算sizeClasses表格
private int sizeClasses() {
    int normalMaxSize = -1;
    int index = 0;
    int size = 0;
    // #1
    int log2Group = LOG2_QUANTUM;
    int log2Delta = LOG2_QUANTUM;
    int ndeltaLimit = 1 << LOG2_SIZE_CLASS_GROUP;
    // #2
    int nDelta = 0;
    while (nDelta < ndeltaLimit) {
        size = sizeClass(index++, log2Group, log2Delta, nDelta++);
    }
    log2Group += LOG2_SIZE_CLASS_GROUP;
    // #3
    while (size < chunkSize) {
        nDelta = 1;
        while (nDelta <= ndeltaLimit && size < chunkSize) {
            size = sizeClass(index++, log2Group, log2Delta, nDelta++);
            normalMaxSize = size;
        }
        log2Group++;
        log2Delta++;
    }
    //chunkSize must be normalMaxSize
    assert chunkSize == normalMaxSize;
    //return number of size index
    return index;
}
LOG2_QUANTUM=4
LOG2_SIZE_CLASS_GROUP=2
#1 log2Group,log2Delta都是从LOG2_QUANTUM开始
ndeltaLimit为2^LOG2_SIZE_CLASS_GROUP,即内存块size以4个为一组进行分组
#2 初始化第0组
nDelta从0开始
sizeClass方法计算sizeClasses每一行内容
注意:第0组后log2Group增加LOG2_SIZE_CLASS_GROUP,而log2Delta不变
#3 初始化后面的size
nDelta从1开始
每组log2Group+1,log2Delta+1
将log2Group=log2Delta+LOG2_SIZE_CLASS_GROUP代入计算公式中,得到
size = 1 << (log2Delta+LOG2_SIZE_CLASS_GROUP) + nDelta * (1 << log2Delta)
size = (nDelta + 2 ^ LOG2_SIZE_CLASS_GROUP) * (1 << log2Delta)
可以看到,每个内存块size都是(1 << log2Delta)的倍数
从第二组开始,每组内这个倍数依次是5,6,7,8
每组内相邻行大小增量为(1 << log2Delta),相邻组之间(1 << log2Delta)翻倍。
Netty默认的配置一个page的大小是2^13,即为8KB,默认的一个chunk的大小为16777216,即16MB。sizeClasses表格内存如下:

Netty内存池中管理了大小不同的内存块,对于这些不同大小的内存块,Netty划分为不同的等级Small,Normal,Huge。Huge是大于chunkSize的内存块,不在表格中,这里也不讨论。
sizeClasses表格可以分为两部分
- isSubPage为1的size为Small内存块,其他为Normal内存块。 
 分配Small内存块,需要找到对应的index
 通过size2SizeIdx方法计算index
 比如需要分配一个90字节的内存块,需要从sizeClasses表格找到第一个大于90的内存块size,即96,其index为5。
- Normal内存块必须是page的倍数。 
 将isMultipageSize为1的行取出组成另一个表格
  
PoolChunk中分配Normal内存块需求查询对应的pageIdx。
比如要分配一个50000字节的内存块,需要从这个新表格找到第一个大于50000的内存块size,即57344,其pageIdx为6。
通过pages2pageIdxCompute方法计算pageIdx。
下面看一下具体的计算方法
public int size2SizeIdx(int size) {
    if (size == 0) {
        return 0;
    }
    // #1
    if (size > chunkSize) {
        return nSizes;
    }
    // #2
    if (directMemoryCacheAlignment > 0) {
        size = alignSize(size);
    }
    // #3
    if (size <= lookupMaxSize) {
        //size-1 / MIN_TINY
        return size2idxTab[size - 1 >> LOG2_QUANTUM];
    }
    // #4
    int x = log2((size << 1) - 1);
    // #5
    int shift = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1
            ? 0 : x - (LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM);
    int group = shift << LOG2_SIZE_CLASS_GROUP;
    // #6
    int log2Delta = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1
            ? LOG2_QUANTUM : x - LOG2_SIZE_CLASS_GROUP - 1;
    // #7
    int deltaInverseMask = -1 << log2Delta;
    int mod = (size - 1 & deltaInverseMask) >> log2Delta &
              (1 << LOG2_SIZE_CLASS_GROUP) - 1;
    return group + mod;
}
#1 大于chunkSize,就是返回nSizes代表申请的是Huge内存块。
#2 不使用sizeClasses表格,直接将申请内存大小转换为directMemoryCacheAlignment的倍数,directMemoryCacheAlignment默认为0。
#3 SizeClasses将一部分较小的size与对应index记录在size2idxTab作为位图,这里直接查询size2idxTab,避免重复计算
size2idxTab中保存了(size-1)/(2^LOG2_QUANTUM) --> idx的对应关系。
从sizeClasses方法可以看到,sizeClasses表格中每个size都是(2^LOG2_QUANTUM) 的倍数。
#4 对申请内存大小进行log2的向上取整,就是每组最后一个内存块size。-1是为了避免申请内存大小刚好等于2的指数次幂时被翻倍。
将log2Group = log2Delta + LOG2_SIZE_CLASS_GROUP,nDelta=2^LOG2_SIZE_CLASS_GROUP代入计算公式,可得
lastSize = 1 << (log2Group +  1)
即x = log2Group +  1
#5 shift, 当前在第几组,从0开始(sizeClasses表格中0~3行为第0组,4~7行为第1组,以此类推,不是log2Group)
x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1,即log2Group < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM ,满足该条件的是第0组的size,这时shift固定是0。
从sizeClasses方法可以看到,除了第0组,都满足shift = log2Group -  LOG2_QUANTUM - (LOG2_SIZE_CLASS_GROUP - 1)。
shift << LOG2_SIZE_CLASS_GROUP就是该组第一个内存块size的索引
#6 计算log2Delta
第0组固定是LOG2_QUANTUM
除了第0组,将nDelta = 2^LOG2_SIZE_CLASS_GROUP代入计算公式
lastSize = ( 2^LOG2_SIZE_CLASS_GROUP + 2^LOG2_SIZE_CLASS_GROUP ) * (1 << log2Delta)
lastSize =  (1 << log2Delta) << LOG2_SIZE_CLASS_GROUP << 1
#7 前面已经定位到第几组了,下面要找到申请内存大小应分配在该组第几位
这里要找到比申请内存大的最小size。
申请内存大小可以理解为上一个size加上一个不大于(1 << log2Delta)的值,即
(nDelta - 1 + 2^LOG2_SIZE_CLASS_GROUP) * (1 << log2Delta) + n, 备注:0 < n <= (1 << log2Delta)
注意,nDelta - 1就是mod
& deltaInverseMask,将申请内存大小最后log2Delta个bit位设置为0,可以理解为减去n
>> log2Delta,右移log2Delta个bit位,就是除以(1 << log2Delta),结果就是(nDelta - 1 + 2 ^ LOG2_SIZE_CLASS_GROUP)
&  (1 << LOG2_SIZE_CLASS_GROUP) - 1, 取最后的LOG2_SIZE_CLASS_GROUP个bit位的值,结果就是mod
size - 1,是为了申请内存等于内存块size时避免分配到下一个内存块size中,即n == (1 << log2Delta)的场景。
疑问:既然右移log2Delta个bit位,那为什么前面要将log2Delta个bit位设置为0?
第0组由于log2Group等于log2Delta,代入计算公式如下
1 << log2Delta + (nDelta - 1) * (1 << log2Delta) + n, 备注:0 < n <= (1 << log2Delta)
nDelta * (1 << log2Delta) + n
所以第0组nDelta从0开始,mod = nDelta
pages2pageIdxCompute方法计算pageIdx逻辑与size2SizeIdx方法类似,只是将LOG2_QUANTUM变量换成了pageShifts,这里不再重复。
SizeClasses是给PoolArena(内存池),PoolChunk(内存块)提供服务的,建议大家结合后面分析PoolArena,PoolChunk的文章一起理解。
如果大家对SizeClasses具体算法不感兴趣,只有理解SizeClasses类中利用sizeClasses表格,为PoolArena,PoolChunk提供计算index,pageIdx索引的方法,也可以帮助大家理解后面解析PoolArena,PoolChunk的文章。
下面贴出sizeClasses完整表格(可复制到Excle,以|分列)
| index  | log2Group  | log2Delta  | nDelta  | isMultiPageSize  | isSubPage  | log2DeltaLookup  | size      | usize  |
| 0      | 4          | 4          | 0       | 0                | 1          | 4                | 16        |        |
| 1      | 4          | 4          | 1       | 0                | 1          | 4                | 32        |        |
| 2      | 4          | 4          | 2       | 0                | 1          | 4                | 48        |        |
| 3      | 4          | 4          | 3       | 0                | 1          | 4                | 64        |        |
| 4      | 6          | 4          | 1       | 0                | 1          | 4                | 80        |        |
| 5      | 6          | 4          | 2       | 0                | 1          | 4                | 96        |        |
| 6      | 6          | 4          | 3       | 0                | 1          | 4                | 112       |        |
| 7      | 6          | 4          | 4       | 0                | 1          | 4                | 128       |        |
| 8      | 7          | 5          | 1       | 0                | 1          | 5                | 160       |        |
| 9      | 7          | 5          | 2       | 0                | 1          | 5                | 192       |        |
| 10     | 7          | 5          | 3       | 0                | 1          | 5                | 224       |        |
| 11     | 7          | 5          | 4       | 0                | 1          | 5                | 256       |        |
| 12     | 8          | 6          | 1       | 0                | 1          | 6                | 320       |        |
| 13     | 8          | 6          | 2       | 0                | 1          | 6                | 384       |        |
| 14     | 8          | 6          | 3       | 0                | 1          | 6                | 448       |        |
| 15     | 8          | 6          | 4       | 0                | 1          | 6                | 512       |        |
| 16     | 9          | 7          | 1       | 0                | 1          | 7                | 640       |        |
| 17     | 9          | 7          | 2       | 0                | 1          | 7                | 768       |        |
| 18     | 9          | 7          | 3       | 0                | 1          | 7                | 896       |        |
| 19     | 9          | 7          | 4       | 0                | 1          | 7                | 1024      | 1K     |
| 20     | 10         | 8          | 1       | 0                | 1          | 8                | 1280      | 1.25K  |
| 21     | 10         | 8          | 2       | 0                | 1          | 8                | 1536      | 1.5K   |
| 22     | 10         | 8          | 3       | 0                | 1          | 8                | 1792      | 1.75K  |
| 23     | 10         | 8          | 4       | 0                | 1          | 8                | 2048      | 2K     |
| 24     | 11         | 9          | 1       | 0                | 1          | 9                | 2560      | 2.5K   |
| 25     | 11         | 9          | 2       | 0                | 1          | 9                | 3072      | 3K     |
| 26     | 11         | 9          | 3       | 0                | 1          | 9                | 3584      | 3.5K   |
| 27     | 11         | 9          | 4       | 0                | 1          | 9                | 4096      | 4K     |
| 28     | 12         | 10         | 1       | 0                | 1          | 0                | 5120      | 5K     |
| 29     | 12         | 10         | 2       | 0                | 1          | 0                | 6144      | 6K     |
| 30     | 12         | 10         | 3       | 0                | 1          | 0                | 7168      | 7K     |
| 31     | 12         | 10         | 4       | 1                | 1          | 0                | 8192      | 8K     |
| 32     | 13         | 11         | 1       | 0                | 1          | 0                | 10240     | 10K    |
| 33     | 13         | 11         | 2       | 0                | 1          | 0                | 12288     | 12K    |
| 34     | 13         | 11         | 3       | 0                | 1          | 0                | 14336     | 14K    |
| 35     | 13         | 11         | 4       | 1                | 1          | 0                | 16384     | 16K    |
| 36     | 14         | 12         | 1       | 0                | 1          | 0                | 20480     | 20K    |
| 37     | 14         | 12         | 2       | 1                | 1          | 0                | 24576     | 24K    |
| 38     | 14         | 12         | 3       | 0                | 1          | 0                | 28672     | 28K    |
| 39     | 14         | 12         | 4       | 1                | 0          | 0                | 32768     | 32K    |
| 40     | 15         | 13         | 1       | 1                | 0          | 0                | 40960     | 40K    |
| 41     | 15         | 13         | 2       | 1                | 0          | 0                | 49152     | 48K    |
| 42     | 15         | 13         | 3       | 1                | 0          | 0                | 57344     | 56K    |
| 43     | 15         | 13         | 4       | 1                | 0          | 0                | 65536     | 64K    |
| 44     | 16         | 14         | 1       | 1                | 0          | 0                | 81920     | 80K    |
| 45     | 16         | 14         | 2       | 1                | 0          | 0                | 98304     | 96K    |
| 46     | 16         | 14         | 3       | 1                | 0          | 0                | 114688    | 112K   |
| 47     | 16         | 14         | 4       | 1                | 0          | 0                | 131072    | 128K   |
| 48     | 17         | 15         | 1       | 1                | 0          | 0                | 163840    | 160K   |
| 49     | 17         | 15         | 2       | 1                | 0          | 0                | 196608    | 192K   |
| 50     | 17         | 15         | 3       | 1                | 0          | 0                | 229376    | 224K   |
| 51     | 17         | 15         | 4       | 1                | 0          | 0                | 262144    | 256K   |
| 52     | 18         | 16         | 1       | 1                | 0          | 0                | 327680    | 320K   |
| 53     | 18         | 16         | 2       | 1                | 0          | 0                | 393216    | 384K   |
| 54     | 18         | 16         | 3       | 1                | 0          | 0                | 458752    | 448K   |
| 55     | 18         | 16         | 4       | 1                | 0          | 0                | 524288    | 512K   |
| 56     | 19         | 17         | 1       | 1                | 0          | 0                | 655360    | 640K   |
| 57     | 19         | 17         | 2       | 1                | 0          | 0                | 786432    | 768K   |
| 58     | 19         | 17         | 3       | 1                | 0          | 0                | 917504    | 896K   |
| 59     | 19         | 17         | 4       | 1                | 0          | 0                | 1048576   | 1M     |
| 60     | 20         | 18         | 1       | 1                | 0          | 0                | 1310720   | 1.25M  |
| 61     | 20         | 18         | 2       | 1                | 0          | 0                | 1572864   | 1.5M   |
| 62     | 20         | 18         | 3       | 1                | 0          | 0                | 1835008   | 1.75M  |
| 63     | 20         | 18         | 4       | 1                | 0          | 0                | 2097152   | 2M     |
| 64     | 21         | 19         | 1       | 1                | 0          | 0                | 2621440   | 2.5M   |
| 65     | 21         | 19         | 2       | 1                | 0          | 0                | 3145728   | 3M     |
| 66     | 21         | 19         | 3       | 1                | 0          | 0                | 3670016   | 3.5M   |
| 67     | 21         | 19         | 4       | 1                | 0          | 0                | 4194304   | 4M     |
| 68     | 22         | 20         | 1       | 1                | 0          | 0                | 5242880   | 5M     |
| 69     | 22         | 20         | 2       | 1                | 0          | 0                | 6291456   | 6M     |
| 70     | 22         | 20         | 3       | 1                | 0          | 0                | 7340032   | 7M     |
| 71     | 22         | 20         | 4       | 1                | 0          | 0                | 8388608   | 8M     |
| 72     | 23         | 21         | 1       | 1                | 0          | 0                | 10485760  | 10M    |
| 73     | 23         | 21         | 2       | 1                | 0          | 0                | 12582912  | 12M    |
| 74     | 23         | 21         | 3       | 1                | 0          | 0                | 14680064  | 14M    |
| 75     | 23         | 21         | 4       | 1                | 0          | 0                | 16777216  | 16M    |
如果您觉得本文不错,欢迎关注我的微信公众号,系列文章持续更新中。您的关注是我坚持的动力!

Netty源码解析 -- 内存对齐类SizeClasses的更多相关文章
- Netty源码解析 -- 内存池与PoolArena
		我们知道,Netty使用直接内存实现Netty零拷贝以提升性能, 但直接内存的创建和释放可能需要涉及系统调用,是比较昂贵的操作,如果每个请求都创建和释放一个直接内存,那性能肯定是不能满足要求的. 这时 ... 
- Netty源码解析 -- PoolChunk实现原理
		本文主要分享Netty中PoolChunk如何管理内存. 源码分析基于Netty 4.1.52 内存管理算法 首先说明PoolChunk内存组织方式. PoolChunk的内存大小默认是16M,Net ... 
- Netty源码解析 -- PoolSubpage实现原理
		前面文章说了PoolChunk如何管理Normal内存块,本文分享PoolSubpage如何管理Small内存块. 源码分析基于Netty 4.1.52 内存管理算法 PoolSubpage负责管理S ... 
- Netty源码解析 -- PoolChunk实现原理(jemalloc 3的算法)
		前面文章已经分享了Netty如何实现jemalloc 4算法管理内存. 本文主要分享Netty 4.1.52之前版本中,PoolChunk如何使用jemalloc 3算法管理内存. 感兴趣的同学可以对 ... 
- Netty源码解析—客户端启动
		Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ... 
- Netty 源码解析(三): Netty 的 Future 和 Promise
		今天是猿灯塔“365篇原创计划”第三篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel 当前:Ne ... 
- Netty 源码解析(九): connect 过程和 bind 过程分析
		原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第九篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ... 
- Netty 源码解析(八): 回到 Channel 的 register 操作
		原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ... 
- Netty 源码解析(六): Channel 的 register 操作
		原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第六篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一 ):开始 Netty ... 
随机推荐
- pycharm2018.1下载激活(mac平台)
			此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: pycharm官网下载地址:http://www.jetbrains.com/pycharm/download/ 激活前准备工作 ... 
- CentOS 6编译安装Redis
			[root@localhost ~]# vim /etc/sysconfig/iptables # 添加如下:-A INPUT -m state –state NEW -m tcp -p tcp –d ... 
- MySQL备份和恢复[4]-xtrabackup备份工具
			xtrabackup工具介绍 Percona 公司 官网:www.percona.com percona-server InnoDB --> XtraDB Xtrabackup备份工具 perc ... 
- HTML轮播(1)
			前言 要想实现轮播,我们就得先把最基础的功能实现,那就是滚动,实现了滚动后就可以继续扩展,完成更多想要的效果 CSS <style> #LB { width: 100%; height: ... 
- spring-boot-route(二十二)实现邮件发送功能
			在项目开发中,除了需要短信验证外,有时候为了节省 短信费也会使用邮件发送.在Spring项目中发送邮件需要封装复杂的消息体,不太方便.而在Spring Boot项目中发送邮件就太简单了,下面一起来看看 ... 
- Python基础知识点整理(详细)
			Python知识点整理(详细) 输出函数 print()可以向屏幕打印内容,或者在打开指定文件后,向文件中输入内容 输入函数 input([prompt])[prompt] 为输入的提示字符.该函数返 ... 
- JS里各种类型的循环
			for... for( 初始条件; 判断条件; 递增条件 ) { ... } for ... in 可以把一个对象里面的所有属性依次循环出来 var person = { name: 'Jack', ... 
- ceil中有-0啊
			这里主要是有一点: 1 Math.ceil(d1) ceil 方法上有这么一段注释:If the argument value is less than zero but greater ... 
- ECMAScript 6 入门  - 阮一峰
			body #home { width: 100%; max-width: 1368px } #inlineFrame { width: 100%; height: calc(100vh - 30px) ... 
- undefined reference to 'mq_open'
			验证 UNPv2里的一个例子时,连接时出现 undefined reference to 'mq_open' 错误. man mq_open ,发现里面有这么一句话 :link with -lrt . ... 
