【Netty 专栏】深入浅出 Netty 内存管理 PoolChunkList

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

点击上方“芋道源码”,选择“置顶公众号”

技术文章第一时间送达!


摘要: 原创出处 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<T> nextList;
    private final int minUsage;
    private final int maxUsage;

    private PoolChunk<T> head;
    private PoolChunkList<T> prevList;
    ...
}

从代码实现可以看出,每个PoolChunkList实例维护了一个PoolChunk链表,自身也形成一个链表,为何要这么实现?

【Netty 专栏】深入浅出 Netty 内存管理 PoolChunkList
img

Paste_Image.png

随着chunk中page的不断分配和释放,会导致很多碎片内存段,大大增加了之后分配一段连续内存的失败率,针对这种情况,可以把内存使用率较大的chunk放到PoolChunkList链表更后面,具体实现如下:

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

    for (PoolChunk<T> 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<T> chunk, long handle) {
    chunk.free(handle);
    if (chunk.usage() < minUsage) {
        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 感兴趣,欢迎加入我的知识星球一起交流。

【Netty 专栏】深入浅出 Netty 内存管理 PoolChunkList

知识星球

目前在知识星球(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 篇++

源码不易↓↓↓

点赞支持老艿艿↓↓