美文网首页nettynettyjava进阶干货
深入浅出Netty内存管理 PoolChunkList

深入浅出Netty内存管理 PoolChunkList

作者: 美团Java | 来源:发表于2016-08-17 18:24 被阅读6426次

    前面两篇分别分析了PoolChunk和PoolSubpage的实现,本文主要分析管理PoolChunk生命周期的PoolChunkList。
    1、深入浅出Netty内存管理 PoolChunk
    2、深入浅出Netty内存管理 PoolSubpage

    PoolChunkList

    PoolChunkList负责管理多个chunk的生命周期,在此基础上对内存分配进行进一步的优化。

    final class PoolChunkList<T> implements PoolChunkListMetric {
        
        private final PoolChunkList<T> nextList;
        private final int minUsage;
        private final int maxUsage;
    
        private PoolChunk<T> head;
        private PoolChunkList<T> prevList;
        ...
    }
    

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

    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链表中前后移动。

    END。
    我是占小狼。
    在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。
    如果读完觉得有收获的话,记得关注和点赞哦。
    非要打赏的话,我也是不会拒绝的。

    相关文章

      网友评论

      • 黄太洪:我想问一下 把内存使用率较大的chunk放到PoolChunkList链表更后面 这和内存连不连续有什么关系吗?

      本文标题:深入浅出Netty内存管理 PoolChunkList

      本文链接:https://www.haomeiwen.com/subject/gormsttx.html