netty内存算法小析(上)

Posted 24HoursFor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了netty内存算法小析(上)相关的知识,希望对你有一定的参考价值。


    Java世界里的内存管理统统交给JVM总管,他会帮我们定时的清理掉垃圾。事情总没有完美的,堆外内存就需要我们自己来管理,堆维护着堆外的引用。netty就是一个实践者。

     编程世界,底层建筑决定上层的建筑。在应用端,我们分配堆外堆内内存只需调用对应的内存的分配就可以得到对应的已经分配好的内存空间,如下图:

           内存的分配器有池化和堆内的之分:大致可以总结为这五种

  PooledHeapByteBuf:池化的基于堆内存的缓冲区。

  PooledDirectByteBuf:池化的基于直接内存的缓冲区。

  PooledUnsafeDirectByteBuf:池化的基于Unsafe和直接内存实现的缓冲区。

  UnPooledHeapByteBuf:非池化的基于堆内存的缓冲区。

  UnPooledDirectByteBuf:非池化的基于直接内存的缓冲区

      以上为上层的建筑,下面说下等层的建筑。netty自己实现一套内存分配的算法,按照官方的说法的叫做jemalloc。做个类比,在电商的物流配送中,比如小件商品可以从同城仓库出,比如大件商品类似家电那就可能要从省内仓库出货 。不同的规格不同的待遇。那么netty是怎么规划的呢?

        Netty的PooledByteBuf把容量划分四个标准tiny(16,512)、small[512,8K)、normal[8K,16M]、huge[16M,)这四种类型。其中tiny和small在一个page里面分配。Normal是多个page组成。Huge是单独分配。里面有个非常重要的临界点,那就是PoolChunk,他是一个page的意思。每个PoolChunk可以分配8KB*1024的内存。那么这个PoolChunk是怎么设计的呢?

       PoolChunk 采用类似的二叉树的方式。总共有1024个page的。形成11层的结构。这样设计就会引入概念,深度depth。

netty内存算法小析(上)


netty内存算法小析(上)

       且看PoolChunk的源码:

   

netty内存算法小析(上)

    

       至于分配策略呢?看看他代码是怎么写的。这个d的参数就是深度,那么他的设计是这样的,因为每一层的的page数量是一定的,比如有个变量depthMap[1024]=11 代表这个page在第11层,而depthMap[511]=10 代表page就在10层,那么如果这个page被分配过后他的value就会变了,假如1024这个节点被分配,那么depthMap[1024]=12,他的父节点也会累计加1,表示已分配过。

netty内存算法小析(上)

     那么问题来,如果分配的内存的小于8KB呢?那么他就会对这个 PoolChunk进行切分,切成多个PoolSubpage,不同的对待,总是从最底层的找到的对应page来进行分配。   

netty内存算法小析(上)

      那么PoolSubpage 是怎么切分段和分配内存的呢?我就挺有意思。翻下代码

      netty内存算法小析(上)

      bitmap的默认长度为8,这里解释一下为什么只需要8个元素:其中分配内存大小都是处理过的,最小为16,说明一个page可以分成8192/16 = 512个内存段,一个long有64位,可以描述64个内存段,这样只需要512/64 = 8个long就可以描述全部内存段了。

      

netty内存算法小析(上)

       同时,用Long类型的来表示呢?且看是如何分配内存,上代码!


   代码和

以上是关于netty内存算法小析(上)的主要内容,如果未能解决你的问题,请参考以下文章

Python之美[从菜鸟到高手]--NotImplemented小析

支撑百万级并发,Netty如何实现高性能内存管理

关于synchronized与volatile的小析

Netty源码_内存管理(jemalloc4)

Netty 内存管理: PooledByteBufAllocator & PoolArena 代码探险[1]

Netty内存池之PoolChunk