Netty-内存池源码三 (SizeClasses 前情预热)
内存池核心类如下:
- PooledByteBufAllocator
- PooledUnsafeDirectByteBuf
- PooledUnsafeDirectByteBuf
- PoolThreadCache
- MemoryRegionCache
- PoolArena
- SizeClasses 本期介绍
- PoolChunk
- LongPriorityQueue
- LongLongHashMap
- PoolSubpage
上一期介绍了【PooledByteBufAllocator
】类,从中可知它又将 内存分配的工作 交给了 【PoolArena
】类
若要分析 【PoolArena
】 首先要分析其父类 【SizeClasses
】。
在jemalloc3中 是没有【SizeClasses
】类的, 而jemalloc4 相较于 jemalloc3 最大的提升是进一步优化内存碎片的问题, 这也是【SizeClasses
】的由来。
在分析【SizeClasses
】之前,我们需要对Netty中的 内存规格进行简单的讲解。
jemalloc3中,对内存规格的划分如下图:
从中可发现,在Small级别的内存分配中会存在大量的内存碎片,比如 某业务要使用 1025B的内存,按照jemalloc3算法就会申请 2048B的 内存块, 这就会导致50%的内存碎片。
jemalloc4中,对内存规格的划分如下图:
从上图可看到, 当 某业务要使用1025B的内存时,jemalloc4算法会申请1280B 的内存块,这就大大减少了内存碎片。 同样也可以看出,jemalloc4取消了 Tiny级别的内存规格。
【SizeClasses
】 该类的主要工作就是 按照 chunkSize 16MB 划分成了 4张表, 其实完全可以把它当作成一个虚拟的数据库,里面存在 4张表
- sizeClasses 总表 , 维护着 各个内存规格的详细信息
- sizeIdx2sizeTab 维护着 index 和 size的关系
- pageIdx2sizeTab 维护着 pageSize 倍数的内存规格表
- size2idxTab 维护着小于等于 4KB(4096) 规格的表
【SizeClasses
】类大致结构如下图:
sizeClasses
该表维护了一个二维数组 ,具体如下:
index | log2Group | log2Delta | nDelta | isMultiPageSize | isSubPage | log2DeltaLookup | size(虚) | Unit |
---|---|---|---|---|---|---|---|---|
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 | |
20 | 10 | 8 | 1 | 0 | 1 | 8 | 1280 | |
21 | 10 | 8 | 2 | 0 | 1 | 8 | 1536 | |
22 | 10 | 8 | 3 | 0 | 1 | 8 | 1792 | |
23 | 10 | 8 | 4 | 0 | 1 | 8 | 2048 | |
24 | 11 | 9 | 1 | 0 | 1 | 9 | 2560 | |
25 | 11 | 9 | 2 | 0 | 1 | 9 | 3072 | |
26 | 11 | 9 | 3 | 0 | 1 | 9 | 3584 | |
27 | 11 | 9 | 4 | 0 | 1 | 9 | 4096 | 4KB |
28 | 12 | 10 | 1 | 0 | 1 | 0 | 5120 | |
29 | 12 | 10 | 2 | 0 | 1 | 0 | 6144 | |
30 | 12 | 10 | 3 | 0 | 1 | 0 | 7168 | |
31 | 12 | 10 | 4 | 1 | 1 | 0 | 8192 | 8KB |
32 | 13 | 11 | 1 | 0 | 1 | 0 | 10240 | 10KB |
33 | 13 | 11 | 2 | 0 | 1 | 0 | 12288 | 12KB |
34 | 13 | 11 | 3 | 0 | 1 | 0 | 14336 | 14KB |
35 | 13 | 11 | 4 | 1 | 1 | 0 | 16384 | 16KB |
36 | 14 | 12 | 1 | 0 | 1 | 0 | 20480 | 20KB |
37 | 14 | 12 | 2 | 1 | 1 | 0 | 24576 | 24KB |
38 | 14 | 12 | 3 | 0 | 1 | 0 | 28672 | 28KB |
39 | 14 | 12 | 4 | 1 | 0 | 0 | 32768 | 32KB |
40 | 15 | 13 | 1 | 1 | 0 | 0 | 40960 | 40KB |
41 | 15 | 13 | 2 | 1 | 0 | 0 | 49152 | 48KB |
42 | 15 | 13 | 3 | 1 | 0 | 0 | 57344 | 56KB |
43 | 15 | 13 | 4 | 1 | 0 | 0 | 65536 | 64KB |
44 | 16 | 14 | 1 | 1 | 0 | 0 | 81920 | 80KB |
45 | 16 | 14 | 2 | 1 | 0 | 0 | 98304 | 96KB |
46 | 16 | 14 | 3 | 1 | 0 | 0 | 114688 | 112KB |
47 | 16 | 14 | 4 | 1 | 0 | 0 | 131072 | 128KB |
48 | 17 | 15 | 1 | 1 | 0 | 0 | 163840 | 160KB |
49 | 17 | 15 | 2 | 1 | 0 | 0 | 196608 | 192KB |
50 | 17 | 15 | 3 | 1 | 0 | 0 | 229376 | 224KB |
51 | 17 | 15 | 3 | 1 | 0 | 0 | 262144 | 256KB |
52 | 18 | 16 | 1 | 1 | 0 | 0 | 327680 | 320KB |
53 | 18 | 16 | 2 | 1 | 0 | 0 | 393216 | 384KB |
54 | 18 | 16 | 3 | 1 | 0 | 0 | 458752 | 448KB |
55 | 18 | 16 | 4 | 1 | 0 | 0 | 524288 | 512KB |
56 | 19 | 17 | 1 | 1 | 0 | 0 | 655360 | 640KB |
57 | 19 | 17 | 2 | 1 | 0 | 0 | 786432 | 768KB |
58 | 19 | 17 | 3 | 1 | 0 | 0 | 917504 | 896KB |
59 | 19 | 17 | 4 | 1 | 0 | 0 | 1048576 | 1.0MB |
60 | 20 | 18 | 1 | 1 | 0 | 0 | 1310720 | 1.25MB |
61 | 20 | 18 | 2 | 1 | 0 | 0 | 1572864 | 1.5MB |
62 | 20 | 18 | 3 | 1 | 0 | 0 | 1835008 | 1.75MB |
63 | 20 | 18 | 4 | 1 | 0 | 0 | 2097152 | 2MB |
64 | 21 | 19 | 1 | 1 | 0 | 0 | 2621440 | 2.5MB |
65 | 21 | 19 | 2 | 1 | 0 | 0 | 3145728 | 3MB |
66 | 21 | 19 | 3 | 1 | 0 | 0 | 3670016 | 3.5MB |
67 | 21 | 19 | 4 | 1 | 0 | 0 | 4194304 | 4MB |
68 | 22 | 20 | 1 | 1 | 0 | 0 | 5242880 | 5MB |
69 | 22 | 20 | 2 | 1 | 0 | 0 | 6291456 | 6MB |
70 | 22 | 20 | 3 | 1 | 0 | 0 | 7340030 | 7MB |
71 | 22 | 20 | 4 | 1 | 0 | 0 | 8388608 | 8MB |
72 | 23 | 21 | 1 | 1 | 0 | 0 | 10485760 | 10MB |
73 | 23 | 21 | 2 | 1 | 0 | 0 | 12582912 | 12MB |
74 | 23 | 21 | 3 | 1 | 0 | 0 | 14680064 | 14MB |
75 | 23 | 21 | 4 | 1 | 0 | 0 | 16777216 | 16MB |
从上表中可知,数组长度 76。每一列表示的含义如下:
-
index
: 由 0 开始的自增序列号,表示每个 size 类型的索引。 -
log2Group
: 表示每个 size 它所对应的组。以每 4 行为一组,一共有 19 组。
第 0 组比较特殊 值为4。
因此,我们应该从第 1 组开始,起始值为 6,每组的 log2Group 是在上一组的值 +1。
-
log2Delta
: 表示当前序号所对应的 size 和前一个序号所对应的 size 的差值的 log2 的值。例如: index=6 对应的 size = 112,index=7 对应的 size= 128,因此 index=7 的 log2Delta(7) = log2(128-112)=4。
规律:其实 log2Delta=log2Group-2。
-
nDelta
: 表示组内增量的倍数。第 0 组也是比较特殊,nDelta 是从 0 开始 + 1。而其余组是从 1 开始 +1 -
isMultiPageSize
: 表示当前 size 是否是 pageSize(默认值: 8192) 的整数倍。后续会把 isMultiPageSize=1 的行单独整理成一张表,你会发现有 40 个 isMultiPageSize=1 的行。 -
isSubPage
: 表示当前 size 是否为一个 subPage 类型,jemalloc4 会根据这个值采取不同的内存分配策略。 -
log2DeltaLookup
: 当 index<=27 时,其值和 log2Delta 相等,当index>27,其值为 0。
jemalloc4 求 SIZE 的公式:
公式1: size = (1 << log2Group) + nDelta (1<<log2Delta)*
公式2: log2Group = log2Delta + 2
公式2带入公式1可得:
**size = (1 << log2Delta + 2) + nDelta * (1<<log2Delta) **
进一步 整理简化 最终可得出:
size = (1<< log2Delta) * (nDelta + 4)
由最终整理后的公式 size = (1<< log2Delta) * (nDelta + 4) 可知两个结论:
结论一: 每一组中每行的log2Delta是相同的, 而nDelta的范围是 [1,4] ,那么 nDelta +4 的取值范围就是 [5,8],也就是说同一组中的 size是按照 5,6,7,8 倍来增长的。 (除第一组以外)
结论二:每一组的最后一个的 nDelta + 4 = 4 + 4 = 8 => 1<<3,那么 size = 1<< log2Delta+3 。 也就是说除了第一组外, 其它每一组的最后一行 size = 1 << log2Delta
sizeIdx2sizeTab
维护16MB以内所有规格 index 和 size 关系的一张表
index | size(虚) | Unit |
---|---|---|
0 | 16 | |
1 | 32 | |
2 | 48 | |
3 | 64 | |
4 | 80 | |
5 | 96 | |
6 | 112 | |
7 | 128 | |
8 | 160 | |
9 | 192 | |
10 | 224 | |
11 | 256 | |
12 | 320 | |
13 | 384 | |
14 | 448 | |
15 | 512 | |
16 | 640 | |
17 | 768 | |
18 | 896 | |
19 | 1024 | |
20 | 1280 | |
21 | 1536 | |
22 | 1792 | |
23 | 2048 | |
24 | 2560 | |
25 | 3072 | |
26 | 3584 | |
27 | 4096 | 4KB |
28 | 5120 | |
29 | 6144 | |
30 | 7168 | |
31 | 8192 | 8KB |
32 | 10240 | 10KB |
33 | 12288 | 12KB |
34 | 14336 | 14KB |
35 | 16384 | 16KB |
36 | 20480 | 20KB |
37 | 24576 | 24KB |
38 | 28672 | 28KB |
39 | 32768 | 32KB |
40 | 40960 | 40KB |
41 | 49152 | 48KB |
42 | 57344 | 56KB |
43 | 65536 | 64KB |
44 | 81920 | 80KB |
45 | 98304 | 96KB |
46 | 114688 | 112KB |
47 | 131072 | 128KB |
48 | 163840 | 160KB |
49 | 196608 | 192KB |
50 | 229376 | 224KB |
51 | 262144 | 256KB |
52 | 327680 | 320KB |
53 | 393216 | 384KB |
54 | 458752 | 448KB |
55 | 524288 | 512KB |
56 | 655360 | 640KB |
57 | 786432 | 768KB |
58 | 917504 | 896KB |
59 | 1048576 | 1.0MB |
60 | 1310720 | 1.25MB |
61 | 1572864 | 1.5MB |
62 | 1835008 | 1.75MB |
63 | 2097152 | 2MB |
64 | 2621440 | 2.5MB |
65 | 3145728 | 3MB |
66 | 3670016 | 3.5MB |
67 | 4194304 | 4MB |
68 | 5242880 | 5MB |
69 | 6291456 | 6MB |
70 | 7340030 | 7MB |
71 | 8388608 | 8MB |
72 | 10485760 | 10MB |
73 | 12582912 | 12MB |
74 | 14680064 | 14MB |
75 | 16777216 | 16MB |
pageIdx2sizeTab
isMultiPageSize 字段为1的行,会组合成 这张表。 也就该表都是 页(8KB) 的倍数的 size规格。
pageIndex | index(虚) | isMultiPageSize(虚) | num of page(虚) | size | Unit |
---|---|---|---|---|---|
0 | 31 | 1 | 1 | 8192 | 8KB |
1 | 35 | 1 | 2 | 16384 | 16KB |
2 | 37 | 1 | 3 | 24576 | 24KB |
3 | 39 | 1 | 4 | 32768 | 32KB |
4 | 40 | 1 | 5 | 40960 | 40KB |
5 | 41 | 1 | 6 | 49152 | 48KB |
6 | 42 | 1 | 7 | 57344 | 56KB |
7 | 43 | 1 | 8 | 65536 | 64KB |
8 | 44 | 1 | 10 | 81920 | 80KB |
9 | 45 | 1 | 12 | 98304 | 96KB |
10 | 46 | 1 | 14 | 114688 | 112KB |
11 | 47 | 1 | 16 | 131072 | 128KB |
12 | 48 | 1 | 20 | 163840 | 160KB |
13 | 49 | 1 | 24 | 196608 | 192KB |
14 | 50 | 1 | 28 | 229376 | 224KB |
15 | 51 | 1 | 32 | 262144 | 256KB |
16 | 52 | 1 | 40 | 327680 | 320KB |
17 | 53 | 1 | 48 | 393216 | 384KB |
18 | 54 | 1 | 56 | 458752 | 448KB |
19 | 55 | 1 | 64 | 524288 | 512KB |
20 | 56 | 1 | 80 | 655360 | 640KB |
21 | 57 | 1 | 96 | 786432 | 768KB |
22 | 58 | 1 | 112 | 917504 | 896KB |
23 | 59 | 1 | 128 | 1048576 | 1.0MB |
24 | 60 | 1 | 160 | 1310720 | 1.25MB |
25 | 61 | 1 | 192 | 1572864 | 1.5MB |
26 | 62 | 1 | 224 | 1835008 | 1.75MB |
27 | 63 | 1 | 256 | 2097152 | 2MB |
28 | 64 | 1 | 320 | 2621440 | 2.5MB |
29 | 65 | 1 | 384 | 3145728 | 3MB |
30 | 66 | 1 | 448 | 3670016 | 3.5MB |
31 | 67 | 1 | 512 | 4194304 | 4MB |
32 | 68 | 1 | 640 | 5242880 | 5MB |
33 | 69 | 1 | 768 | 6291456 | 6MB |
34 | 70 | 1 | 896 | 7340030 | 7MB |
35 | 71 | 1 | 1024 | 8388608 | 8MB |
36 | 72 | 1 | 1280 | 10485760 | 10MB |
37 | 73 | 1 | 1536 | 12582912 | 12MB |
38 | 74 | 1 | 1792 | 14680064 | 14MB |
39 | 75 | 1 | 2048 | 16777216 | 16MB |
size2idxTab
对size 小于等于 4KB (4096) 的 规格, 做一个细致的划分, 以16B为递增 增量。
由于里面行数太多,这里不展示全部的了,大致如下图:
由于图表的原因 导致篇幅太长,具体的【SizeClasses
】源码分析会到下期文章分析。