Netty原始碼解析 -- 記憶體對齊類SizeClasses

binecy發表於2020-11-22

在學習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表格可以分為兩部分

  1. isSubPage為1的size為Small記憶體塊,其他為Normal記憶體塊。
    分配Small記憶體塊,需要找到對應的index
    通過size2SizeIdx方法計算index
    比如需要分配一個90位元組的記憶體塊,需要從sizeClasses表格找到第一個大於90的記憶體塊size,即96,其index為5。

  2. 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_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      | 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    |

如果您覺得本文不錯,歡迎關注我的微信公眾號,系列文章持續更新中。您的關注是我堅持的動力!

相關文章