乐趣区

关于netty: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 办法计算每个 size 大小
留神:第 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, 即为 1KB, 默认的一个 chunk 的大小为 16777216,即 2MB。sizeClasses 表格内存如下:

size 并不是 sizeClasses 表格的列,这里为了直观而列出。
Netty 内存池中治理了大小不同的内存块,对于这些不同大小的内存块,Netty 划分为不同的等级 Small,Normal,Huge

sizeClasses 表格能够分为两局部

  1. isSubPage 为 1 的 size 为 Small 内存块,其余为 Normal 内存块,而大于 chunkSize 的为 huge 内存块,不在表格中。

调配 Small 内存块,须要找到对应的 index
通过 size2SizeIdx 办法计算 index
比方须要调配一个 360 位的内存块,须要从 sizeClasses 表格找到第一个大于 360 的内存块 size,即 384,其 index 为 13

  1. Normal 内存块必须是 page 的倍数。

将 isMultipageSize 为 1 的行取出组成另一个表格

pageIdx 并不是 sizeClasses 表格的列,它是这个新表格的索引。
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 的对应关系。
#4 对申请内存大小进行 log2 的向上取整,就是每组最初一个内存块 size。- 1 是为了防止申请内存大小刚好等于 2 的指数次幂时被翻倍。
log2Group = log2Delta + LOG2_SIZE_CLASS_GROUPnDelta=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                 |
| 0      | 4          | 4          | 0       | 0                | 1          | 4                | 16  --  2B           |
| 1      | 4          | 4          | 1       | 0                | 1          | 4                | 32  --  4B           |
| 2      | 4          | 4          | 2       | 0                | 1          | 4                | 48  --  6B           |
| 3      | 4          | 4          | 3       | 0                | 1          | 4                | 64  --  8B           |
| 4      | 6          | 4          | 1       | 0                | 1          | 4                | 80  --  10B          |
| 5      | 6          | 4          | 2       | 0                | 1          | 4                | 96  --  12B          |
| 6      | 6          | 4          | 3       | 0                | 1          | 4                | 112  --  14B         |
| 7      | 6          | 4          | 4       | 0                | 1          | 4                | 128  --  16B         |
| 8      | 7          | 5          | 1       | 0                | 1          | 5                | 160  --  20B         |
| 9      | 7          | 5          | 2       | 0                | 1          | 5                | 192  --  24B         |
| 10     | 7          | 5          | 3       | 0                | 1          | 5                | 224  --  28B         |
| 11     | 7          | 5          | 4       | 0                | 1          | 5                | 256  --  32B         |
| 12     | 8          | 6          | 1       | 0                | 1          | 6                | 320  --  40B         |
| 13     | 8          | 6          | 2       | 0                | 1          | 6                | 384  --  48B         |
| 14     | 8          | 6          | 3       | 0                | 1          | 6                | 448  --  56B         |
| 15     | 8          | 6          | 4       | 0                | 1          | 6                | 512  --  64B         |
| 16     | 9          | 7          | 1       | 0                | 1          | 7                | 640  --  80B         |
| 17     | 9          | 7          | 2       | 0                | 1          | 7                | 768  --  96B         |
| 18     | 9          | 7          | 3       | 0                | 1          | 7                | 896  --  112B        |
| 19     | 9          | 7          | 4       | 0                | 1          | 7                | 1024  --  128B       |
| 20     | 10         | 8          | 1       | 0                | 1          | 8                | 1280  --  160B       |
| 21     | 10         | 8          | 2       | 0                | 1          | 8                | 1536  --  192B       |
| 22     | 10         | 8          | 3       | 0                | 1          | 8                | 1792  --  224B       |
| 23     | 10         | 8          | 4       | 0                | 1          | 8                | 2048  --  256B       |
| 24     | 11         | 9          | 1       | 0                | 1          | 9                | 2560  --  320B       |
| 25     | 11         | 9          | 2       | 0                | 1          | 9                | 3072  --  384B       |
| 26     | 11         | 9          | 3       | 0                | 1          | 9                | 3584  --  448B       |
| 27     | 11         | 9          | 4       | 0                | 1          | 9                | 4096  --  512B       |
| 28     | 12         | 10         | 1       | 0                | 1          | 0                | 5120  --  640B       |
| 29     | 12         | 10         | 2       | 0                | 1          | 0                | 6144  --  768B       |
| 30     | 12         | 10         | 3       | 0                | 1          | 0                | 7168  --  896B       |
| 31     | 12         | 10         | 4       | 1                | 1          | 0                | 8192  --  1.0KB      |
| 32     | 13         | 11         | 1       | 0                | 1          | 0                | 10240  --  1.25KB    |
| 33     | 13         | 11         | 2       | 0                | 1          | 0                | 12288  --  1.5KB     |
| 34     | 13         | 11         | 3       | 0                | 1          | 0                | 14336  --  1.75KB    |
| 35     | 13         | 11         | 4       | 1                | 1          | 0                | 16384  --  2.0KB     |
| 36     | 14         | 12         | 1       | 0                | 1          | 0                | 20480  --  2.5KB     |
| 37     | 14         | 12         | 2       | 1                | 1          | 0                | 24576  --  3.0KB     |
| 38     | 14         | 12         | 3       | 0                | 1          | 0                | 28672  --  3.5KB     |
| 39     | 14         | 12         | 4       | 1                | 0          | 0                | 32768  --  4.0KB     |
| 40     | 15         | 13         | 1       | 1                | 0          | 0                | 40960  --  5.0KB     |
| 41     | 15         | 13         | 2       | 1                | 0          | 0                | 49152  --  6.0KB     |
| 42     | 15         | 13         | 3       | 1                | 0          | 0                | 57344  --  7.0KB     |
| 43     | 15         | 13         | 4       | 1                | 0          | 0                | 65536  --  8.0KB     |
| 44     | 16         | 14         | 1       | 1                | 0          | 0                | 81920  --  10.0KB    |
| 45     | 16         | 14         | 2       | 1                | 0          | 0                | 98304  --  12.0KB    |
| 46     | 16         | 14         | 3       | 1                | 0          | 0                | 114688  --  14.0KB   |
| 47     | 16         | 14         | 4       | 1                | 0          | 0                | 131072  --  16.0KB   |
| 48     | 17         | 15         | 1       | 1                | 0          | 0                | 163840  --  20.0KB   |
| 49     | 17         | 15         | 2       | 1                | 0          | 0                | 196608  --  24.0KB   |
| 50     | 17         | 15         | 3       | 1                | 0          | 0                | 229376  --  28.0KB   |
| 51     | 17         | 15         | 4       | 1                | 0          | 0                | 262144  --  32.0KB   |
| 52     | 18         | 16         | 1       | 1                | 0          | 0                | 327680  --  40.0KB   |
| 53     | 18         | 16         | 2       | 1                | 0          | 0                | 393216  --  48.0KB   |
| 54     | 18         | 16         | 3       | 1                | 0          | 0                | 458752  --  56.0KB   |
| 55     | 18         | 16         | 4       | 1                | 0          | 0                | 524288  --  64.0KB   |
| 56     | 19         | 17         | 1       | 1                | 0          | 0                | 655360  --  80.0KB   |
| 57     | 19         | 17         | 2       | 1                | 0          | 0                | 786432  --  96.0KB   |
| 58     | 19         | 17         | 3       | 1                | 0          | 0                | 917504  --  112.0KB  |
| 59     | 19         | 17         | 4       | 1                | 0          | 0                | 1048576  --  128.0KB |
| 60     | 20         | 18         | 1       | 1                | 0          | 0                | 1310720  --  160.0KB |
| 61     | 20         | 18         | 2       | 1                | 0          | 0                | 1572864  --  192.0KB |
| 62     | 20         | 18         | 3       | 1                | 0          | 0                | 1835008  --  224.0KB |
| 63     | 20         | 18         | 4       | 1                | 0          | 0                | 2097152  --  256.0KB |
| 64     | 21         | 19         | 1       | 1                | 0          | 0                | 2621440  --  320.0KB |
| 65     | 21         | 19         | 2       | 1                | 0          | 0                | 3145728  --  384.0KB |
| 66     | 21         | 19         | 3       | 1                | 0          | 0                | 3670016  --  448.0KB |
| 67     | 21         | 19         | 4       | 1                | 0          | 0                | 4194304  --  512.0KB |
| 68     | 22         | 20         | 1       | 1                | 0          | 0                | 5242880  --  640.0KB |
| 69     | 22         | 20         | 2       | 1                | 0          | 0                | 6291456  --  768.0KB |
| 70     | 22         | 20         | 3       | 1                | 0          | 0                | 7340032  --  896.0KB |
| 71     | 22         | 20         | 4       | 1                | 0          | 0                | 8388608  --  1.0MB   |
| 72     | 23         | 21         | 1       | 1                | 0          | 0                | 10485760  --  1.25MB |
| 73     | 23         | 21         | 2       | 1                | 0          | 0                | 12582912  --  1.5MB  |
| 74     | 23         | 21         | 3       | 1                | 0          | 0                | 14680064  --  1.75MB |
| 75     | 23         | 21         | 4       | 1                | 0          | 0                | 16777216  --  2.0MB  |

如果您感觉本文不错,欢送关注我的微信公众号,您的关注是我保持的能源!

退出移动版