Netty-内存池源码三 (SizeClasses 前情预热)
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<
公式2: log2Group = log2Delta + 2
? 公式2带入公式1可得:
? **size = (1 << log2Delta + 2) + nDelta * (1< ? 进一步 整理简化 最终可得出: ? 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 维护16MB以内所有规格 index 和 size 关系的一张表 isMultiPageSize 字段为1的行,会组合成 这张表。 也就该表都是 页(8KB) 的倍数的 size规格。 对size 小于等于 4KB (4096) 的 规格, 做一个细致的划分, 以16B为递增 增量。 由于里面行数太多,这里不展示全部的了,大致如下图: 由于图表的原因 导致篇幅太长,具体的【sizeIdx2sizeTab
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
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
SizeClasses】源码分析会到下期文章分析。