歡迎光臨
每天分享高質量文章

【Netty 專欄】深入淺出 Netty 記憶體管理 PoolChunkList

點擊上方“芋道原始碼”,選擇“置頂公眾號”

技術文章第一時間送達!

原始碼精品專欄

 


摘要: 原創出處 https://www.jianshu.com/p/a1debfe4ff02 「占小狼」歡迎轉載,保留摘要,謝謝!

  • PoolChunkList


前面兩篇分別分析了PoolChunk和PoolSubpage的實現,本文主要分析管理PoolChunk生命周期的PoolChunkList。
1、深入淺出Netty記憶體管理 PoolChunk
2、深入淺出Netty記憶體管理 PoolSubpage

PoolChunkList

PoolChunkList負責管理多個chunk的生命周期,在此基礎上對記憶體分配進行進一步的優化。

final class PoolChunkList<Timplements PoolChunkListMetric {

    private final PoolChunkList nextList;
    private final int minUsage;
    private final int maxUsage;

    private PoolChunk head;
    private PoolChunkList prevList;
    ...
}

從代碼實現可以看出,每個PoolChunkList實體維護了一個PoolChunk鏈表,自身也形成一個鏈表,為何要這麼實現?

img

Paste_Image.png

隨著chunk中page的不斷分配和釋放,會導致很多碎片記憶體段,大大增加了之後分配一段連續記憶體的失敗率,針對這種情況,可以把記憶體使用率較大的chunk放到PoolChunkList鏈表更後面,具體實現如下:

boolean allocate(PooledByteBuf buf, int reqCapacity, int normCapacity) {
    if (head == null) {
        return false;
    }

    for (PoolChunk cur = head;;) {
        long handle = cur.allocate(normCapacity);
        if (handle 0) {
            cur = cur.next;
            if (cur == null) {
                return false;
            }
        } else {
            cur.initBuf(buf, handle, reqCapacity);
            if (cur.usage() >= maxUsage) {   // (1)
                remove(cur);
                nextList.add(cur);
            }
            return true;
        }
    }
}

假設poolChunkList中已經存在多個chunk。當分配完記憶體後,如果當前chunk的使用量超過maxUsage,則把該chunk從當前鏈表中刪除,添加到下一個鏈表中。

但是,隨便chunk中記憶體的釋放,其記憶體使用率也會隨著下降,當下降到minUsage時,該chunk會移動到前一個串列中,實現如下:

boolean free(PoolChunk chunk, long handle) {
    chunk.free(handle);
    if (chunk.usage()         remove(chunk);
        if (prevList == null) {
            assert chunk.usage() == 0;
            return false;
        } else {
            prevList.add(chunk);
            return true;
        }
    }
    return true;
}

從poolChunkList的實現可以看出,每個chunkList的都有一個上下限:minUsage和maxUsage,兩個相鄰的chunkList,前一個的maxUsage和後一個的minUsage必須有一段交叉值進行緩衝,否則會出現某個chunk的usage處於臨界值,而導致不停的在兩個chunk間移動。

所以chunk的生命周期不會固定在某個chunkList中,隨著記憶體的分配和釋放,根據當前的記憶體使用率,在chunkList鏈表中前後移動。




如果你對 Dubbo 感興趣,歡迎加入我的知識星球一起交流。

知識星球

目前在知識星球(https://t.zsxq.com/2VbiaEu)更新瞭如下 Dubbo 原始碼解析如下:

01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽

05. 拓展機制 SPI

06. 執行緒池

07. 服務暴露 Export

08. 服務取用 Refer

09. 註冊中心 Registry

10. 動態編譯 Compile

11. 動態代理 Proxy

12. 服務呼叫 Invoke

13. 呼叫特性 

14. 過濾器 Filter

15. NIO 服務器

16. P2P 服務器

17. HTTP 服務器

18. 序列化 Serialization

19. 集群容錯 Cluster

20. 優雅停機

21. 日誌適配

22. 狀態檢查

23. 監控中心 Monitor

24. 管理中心 Admin

25. 運維命令 QOS

26. 鏈路追蹤 Tracing


一共 60 篇++

原始碼不易↓↓↓

點贊支持老艿艿↓↓

赞(0)

分享創造快樂