溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses

發(fā)布時(shí)間:2021-10-23 16:57:13 來(lái)源:億速云 閱讀:128 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses”,在日常操作中,相信很多人在Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

在學(xué)習(xí)Netty內(nèi)存池之前,我們先了解一下Netty的內(nèi)存對(duì)齊類SizeClasses,它為Netty內(nèi)存池中的內(nèi)存塊提供大小對(duì)齊,索引計(jì)算等服務(wù)方法。
源碼分析基于Netty 4.1.52

Netty內(nèi)存池中每個(gè)內(nèi)存塊size都符合如下計(jì)算公式
size = 1 << log2Group + nDelta * (1 << log2Delta)
log2Group:內(nèi)存塊分組
nDelta:增量乘數(shù)
log2Delta:增量大小的log2值

SizeClasses初始化后,將計(jì)算chunkSize(內(nèi)存池每次向操作系統(tǒng)申請(qǐng)內(nèi)存塊大?。┓秶鷥?nèi)每個(gè)size的值,保存到sizeClasses字段中。
sizeClasses是一個(gè)表格(二維數(shù)組),共有7列,含義如下
index:內(nèi)存塊size的索引
log2Group:內(nèi)存塊分組,用于計(jì)算對(duì)應(yīng)的size
log2Delata:增量大小的log2值,用于計(jì)算對(duì)應(yīng)的size
nDelta:增量乘數(shù),用于計(jì)算對(duì)應(yīng)的size
isMultipageSize:表示size是否為page的倍數(shù)
isSubPage:表示是否為一個(gè)subPage類型
log2DeltaLookup:如果size存在位圖中的,記錄其log2Delta,未使用

sizeClasses負(fù)責(zé)計(jì)算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開(kāi)始
ndeltaLimit為2^LOG2_SIZE_CLASS_GROUP,即內(nèi)存塊size以4個(gè)為一組進(jìn)行分組
#2 初始化第0組
nDelta從0開(kāi)始
sizeClass方法計(jì)算sizeClasses每一行內(nèi)容
注意:第0組后log2Group增加LOG2_SIZE_CLASS_GROUP,而log2Delta不變
#3 初始化后面的size
nDelta從1開(kāi)始
每組log2Group+1,log2Delta+1

log2Group=log2Delta+LOG2_SIZE_CLASS_GROUP代入計(jì)算公式中,得到
size = 1 << (log2Delta+LOG2_SIZE_CLASS_GROUP) + nDelta * (1 << log2Delta)
size = (nDelta + 2 ^ LOG2_SIZE_CLASS_GROUP) * (1 << log2Delta)

可以看到,每個(gè)內(nèi)存塊size都是(1 << log2Delta)的倍數(shù)
從第二組開(kāi)始,每組內(nèi)這個(gè)倍數(shù)依次是5,6,7,8
每組內(nèi)相鄰行大小增量為(1 << log2Delta),相鄰組之間(1 << log2Delta)翻倍。
Netty默認(rèn)的配置一個(gè)page的大小是2^13,即為8KB,默認(rèn)的一個(gè)chunk的大小為16777216,即16MB。sizeClasses表格內(nèi)存如下:
Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses

Netty內(nèi)存池中管理了大小不同的內(nèi)存塊,對(duì)于這些不同大小的內(nèi)存塊,Netty劃分為不同的等級(jí)Small,Normal,Huge。Huge是大于chunkSize的內(nèi)存塊,不在表格中,這里也不討論。

sizeClasses表格可以分為兩部分

  1. isSubPage為1的size為Small內(nèi)存塊,其他為Normal內(nèi)存塊。 分配Small內(nèi)存塊,需要找到對(duì)應(yīng)的index 通過(guò)size2SizeIdx方法計(jì)算index 比如需要分配一個(gè)90字節(jié)的內(nèi)存塊,需要從sizeClasses表格找到第一個(gè)大于90的內(nèi)存塊size,即96,其index為5。

  2. Normal內(nèi)存塊必須是page的倍數(shù)。 將isMultipageSize為1的行取出組成另一個(gè)表格 Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses

PoolChunk中分配Normal內(nèi)存塊需求查詢對(duì)應(yīng)的pageIdx。
比如要分配一個(gè)50000字節(jié)的內(nèi)存塊,需要從這個(gè)新表格找到第一個(gè)大于50000的內(nèi)存塊size,即57344,其pageIdx為6。
通過(guò)pages2pageIdxCompute方法計(jì)算pageIdx。

下面看一下具體的計(jì)算方法

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代表申請(qǐng)的是Huge內(nèi)存塊。
#2 不使用sizeClasses表格,直接將申請(qǐng)內(nèi)存大小轉(zhuǎn)換為directMemoryCacheAlignment的倍數(shù),directMemoryCacheAlignment默認(rèn)為0。
#3 SizeClasses將一部分較小的size與對(duì)應(yīng)index記錄在size2idxTab作為位圖,這里直接查詢size2idxTab,避免重復(fù)計(jì)算
size2idxTab中保存了(size-1)/(2^LOG2_QUANTUM) --> idx的對(duì)應(yīng)關(guān)系。
從sizeClasses方法可以看到,sizeClasses表格中每個(gè)size都是(2^LOG2_QUANTUM) 的倍數(shù)。
#4 對(duì)申請(qǐng)內(nèi)存大小進(jìn)行l(wèi)og2的向上取整,就是每組最后一個(gè)內(nèi)存塊size。-1是為了避免申請(qǐng)內(nèi)存大小剛好等于2的指數(shù)次冪時(shí)被翻倍。
log2Group = log2Delta + LOG2_SIZE_CLASS_GROUPnDelta=2^LOG2_SIZE_CLASS_GROUP代入計(jì)算公式,可得
lastSize = 1 << (log2Group + 1)
x = log2Group + 1
#5 shift, 當(dāng)前在第幾組,從0開(kāi)始(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,這時(shí)shift固定是0。
從sizeClasses方法可以看到,除了第0組,都滿足shift = log2Group - LOG2_QUANTUM - (LOG2_SIZE_CLASS_GROUP - 1)。
shift << LOG2_SIZE_CLASS_GROUP就是該組第一個(gè)內(nèi)存塊size的索引

#6 計(jì)算log2Delta
第0組固定是LOG2_QUANTUM
除了第0組,將nDelta = 2^LOG2_SIZE_CLASS_GROUP代入計(jì)算公式
lastSize = ( 2^LOG2_SIZE_CLASS_GROUP + 2^LOG2_SIZE_CLASS_GROUP ) * (1 << log2Delta)
lastSize = (1 << log2Delta) << LOG2_SIZE_CLASS_GROUP << 1

#7 前面已經(jīng)定位到第幾組了,下面要找到申請(qǐng)內(nèi)存大小應(yīng)分配在該組第幾位
這里要找到比申請(qǐng)內(nèi)存大的最小size。

申請(qǐng)內(nèi)存大小可以理解為上一個(gè)size加上一個(gè)不大于(1 << log2Delta)的值,即
(nDelta - 1 + 2^LOG2_SIZE_CLASS_GROUP) * (1 << log2Delta) + n, 備注:0 < n <= (1 << log2Delta)
注意,nDelta - 1就是mod

& deltaInverseMask,將申請(qǐng)內(nèi)存大小最后log2Delta個(gè)bit位設(shè)置為0,可以理解為減去n
>> log2Delta,右移log2Delta個(gè)bit位,就是除以(1 << log2Delta),結(jié)果就是(nDelta - 1 + 2 ^ LOG2_SIZE_CLASS_GROUP)
& (1 << LOG2_SIZE_CLASS_GROUP) - 1, 取最后的LOG2_SIZE_CLASS_GROUP個(gè)bit位的值,結(jié)果就是mod

size - 1,是為了申請(qǐng)內(nèi)存等于內(nèi)存塊size時(shí)避免分配到下一個(gè)內(nèi)存塊size中,即n == (1 << log2Delta)的場(chǎng)景。

疑問(wèn):既然右移log2Delta個(gè)bit位,那為什么前面要將log2Delta個(gè)bit位設(shè)置為0?

第0組由于log2Group等于log2Delta,代入計(jì)算公式如下
1 << log2Delta + (nDelta - 1) * (1 << log2Delta) + n, 備注:0 < n <= (1 << log2Delta)
nDelta * (1 << log2Delta) + n
所以第0組nDelta從0開(kāi)始,mod = nDelta

pages2pageIdxCompute方法計(jì)算pageIdx邏輯與size2SizeIdx方法類似,只是將LOG2_QUANTUM變量換成了pageShifts,這里不再重復(fù)。

SizeClasses是給PoolArena(內(nèi)存池),PoolChunk(內(nèi)存塊)提供服務(wù)的,建議大家結(jié)合后面分析PoolArena,PoolChunk的文章一起理解。
如果大家對(duì)SizeClasses具體算法不感興趣,只有理解SizeClasses類中利用sizeClasses表格,為PoolArena,PoolChunk提供計(jì)算index,pageIdx索引的方法,也可以幫助大家理解后面解析PoolArena,PoolChunk的文章。

下面貼出sizeClasses完整表格(可復(fù)制到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    |

到此,關(guān)于“Netty源碼解析之如何理解內(nèi)存對(duì)齊類SizeClasses”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI