前面讲过PoolChunk最小得分配单位是page,而page得默认大小是8k,但在实际应用当中,会有很多的小数据,如果小数据也占用一个page的话。那无疑内存将会大大的浪费。针对这种情况,netty就建了个新东西叫PoolSubpage。PoolSubpage的工作和PoolChunk类似,只是PoolSubpage所管理的内存块远小于PoolChunk,且PoolSubpage的内存是从chunk的最深那一层分割的。

首先,看下PoolSubpage的字段

    final PoolChunk<T> chunk;//所属的poolChunkprivate final int memoryMapIdx;//poolchunk的idprivate final int runOffset;//当前page在chunk里的偏移量private final int pageSize;//page大小private final long[] bitmap;//各个poolsubpage的使用状态PoolSubpage<T> prev;//前节点PoolSubpage<T> next;boolean doNotDestroy;//是否能清除int elemSize;//把page分割的大小private int maxNumElems;//总共有多少个elemprivate int bitmapLength;//bitmap需要用到的长度private int nextAvail;//下一个可用节点位置private int numAvail;//可用节点的数量

PollSubPage的字段就只有这些,需要特别注意的就是bitmap,是个long类型的数组,long是64位,每一位都代表多应的节点是否可用。

构造方法

     PoolSubpage(PoolSubpage<T> head, PoolChunk<T> chunk, int memoryMapIdx, int runOffset, int pageSize, int elemSize) {this.chunk = chunk;this.memoryMapIdx = memoryMapIdx;this.runOffset = runOffset;this.pageSize = pageSize;bitmap = new long[pageSize >>> 10]; // pageSize / 16 / 64init(head, elemSize);}

构造方法很简单,要注意的就是bitmap的长度赋值了。为什么会是 pageSize >>>10呢?那是因为用户请求分配的大小在内存分配这条链上已经被normalizeCapacity处理了,这个方法在PoolArena中,最小值是16,而long类型的长度是16,代表一个long类型的数据能表示64个节点是否已经被使用,所以要完整的表示所有的节点数是否被使用 所需要的 long个数= pageSzie /16 / 64 =pageSize/(2^4*2^6)=pageSzie /2^10 =pageSize >>>10。

void init(PoolSubpage<T> head, int elemSize)

   //从IDE里可以看到,这个方法会在两个地方调用,1.初始化;2.subPage被回收后在分配void init(PoolSubpage<T> head, int elemSize) {doNotDestroy = true;this.elemSize = elemSize;//if (elemSize != 0) {//初始化maxNumElems = numAvail = pageSize / elemSize;//计算节点的最大值nextAvail = 0;//把下一节点置为可用bitmapLength = maxNumElems >>> 6;//得到bitmap的长度  相当于 / 64if ((maxNumElems & 63) != 0) {当个数小于64得话,maxNumElems >>> 6=0,所以需要补偿bitmapLength ++;}for (int i = 0; i < bitmapLength; i ++) {//把所有节点置为没有使用状态bitmap[i] = 0;}}//加入到池里,之所以要加入到池里是因为chunk分配了subPage,但并没有把subPage暴露出去,所以需要自己把自己加入到chunk.arena里,以便管理addToPool(head);}

构造方法和字段说完,下面来看看PoolSubPage的核心方法,

long allocate()

     long allocate() {if (elemSize == 0) {return toHandle(0);}//没有可用节点或已经被销毁了if (numAvail == 0 || !doNotDestroy) {return -1;}//获取到可用节点final int bitmapIdx = getNextAvail();//算出可用节点在bitmap里的索引int q = bitmapIdx >>> 6;//计算出long值得第几位表示这个索引int r = bitmapIdx & 63;assert (bitmap[q] >>> r & 1) == 0;//没被使用校验bitmap[q] |= 1L << r;//把long对应得位数置为1if (-- numAvail == 0) {//把可用节点数减一,等于0表示没有可用内存,就把subpage从arena里删除removeFromPool();}//返回获取到得内存索引,是一个long类型,其中高32位代表chunk得id,低32位代表subpage得idreturn toHandle(bitmapIdx);}

接下来看下是如何寻找节点得

    private int getNextAvail() {int nextAvail = this.nextAvail;if (nextAvail >= 0) {//下一节点可用,直接返回this.nextAvail = -1;return nextAvail;}return findNextAvail();}private int findNextAvail() {final long[] bitmap = this.bitmap;final int bitmapLength = this.bitmapLength;for (int i = 0; i < bitmapLength; i ++) {//对bitmap遍历long bits = bitmap[i];if (~bits != 0) {//取非,不等于0说明该long值上有位数是=0的,即说明没有使用完return findNextAvail0(i, bits);}}return -1;}private int findNextAvail0(int i, long bits) {final int maxNumElems = this.maxNumElems;final int baseVal = i << 6;for (int j = 0; j < 64; j ++) {if ((bits & 1) == 0) {//等于0说明该位置还没有被分配int val = baseVal | j;//得出在所有的节点里,这是第几个if (val < maxNumElems) {//小于最大节点数量,就返回这个节点return val;} else {break;}}bits >>>= 1;}return -1;}

到这里,PoolSubPage的分配内存,初始化就讲完了,除了一些位运算有点饶人外,其他的还是比较简单的。

最后看看PoolSubPage是怎么释放内存的

boolean free(PoolSubpage<T> head, int bitmapIdx)

        boolean free(PoolSubpage<T> head, int bitmapIdx) {if (elemSize == 0) {return true;}//获取到对应节点int q = bitmapIdx >>> 6;int r = bitmapIdx & 63;assert (bitmap[q] >>> r & 1) != 0;bitmap[q] ^= 1L << r;//设置位可用setNextAvail(bitmapIdx);//numAvail==0说明之前已经把subpage从arena里删除了,这里重新加入if (numAvail ++ == 0) {addToPool(head);return true;}if (numAvail != maxNumElems) {return true;} else {//下面一整段是做了下性能处理,if (prev == next) {return true;}doNotDestroy = false;removeFromPool();return false;}}

-----------------------------------------------------------------------

百世经纶,扑街之路,不由分说

netty内存-PoolSubpage分析相关推荐

  1. Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述

    Netty源码分析第5章(ByteBuf)---->第5节: directArena分配缓冲区概述 Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上 ...

  2. Netty内存池 (5w长文+史上最全)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...

  3. Netty 内存池(二)内存申请流程

    Netty 内存池(二)内存申请流程 上期带大家了解了一下Netty内存池都有哪些重要的对象,以及这些对象的作用是什么,本期就带大家分析一下线程是如何申请一块内存的.本期由于涉及到了很多变量和位运算, ...

  4. Netty源码分析第7章(编码器和写数据)----第2节: MessageToByteEncoder

    Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEnc ...

  5. CUDA 内存统一分析

    CUDA 内存统一分析 关于CUDA 编程的基本知识,如何编写一个简单的程序,在内存中分配两个可供 GPU 访问的数字数组,然后将它们加在 GPU 上. 本文介绍内存统一,这使得分配和访问系统中任何处 ...

  6. Linux内存技术分析(下)

    Linux内存技术分析(下) 五. 内存使用场景 out of memory 的时代过去了吗?no,内存再充足也不可任性使用. 1.内存的使用场景 · page管理 · slab(kmalloc.内存 ...

  7. Linux内存技术分析(上)

    Linux内存技术分析(上) 一.Linux存储器 限于存储介质的存取速率和成本,现代计算机的存储结构呈现为金字塔型.越往塔顶,存取效率越高.但成本也越高,所以容量也就越小.得益于程序访问的局部性原理 ...

  8. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  9. Java进程占用内存超高分析

    Java进程占用内存超高分析_ 1. 报错 2. 解决 3. 我用到的解决方法 写了一个Java服务,没有定时服务,没有线程池,没有重度的读写,只是对外提供了几个接口,接口的访问量并不高,结果占用内存 ...

  10. 内存泄漏分析 mat 使用 activity泄漏

    https://github.com/square/leakcanarysquare 公司出品mat 下载地址: http://pan.baidu.com/s/1kVPoIxx 两天,一个内存泄漏 a ...

最新文章

  1. Anaconda 使用的一些体验与困惑
  2. 退休是不可能的,90岁还要继续干!
  3. 关于子网划分—为什么全0全1子网号不能使用
  4. C#操作mysql中临时表不自动删除
  5. 信息熵和交叉熵的细节理解
  6. 今日头条野心背后逃不过的10个问题
  7. ITK:减去两个图像
  8. 逻辑回归模型_联邦学习体系下——逻辑回归模型
  9. OpenGL基础16:视角
  10. Linux Kernel 5.0 近日正式面向公众
  11. Apollo中Eureka,metaService,configService关系
  12. python初学入门——————输入输出语句
  13. asp.net中配置使用Sqlite轻型数据库
  14. Python求极限求积分,编程实现
  15. Win7系统怎么开启远程桌面?Win7远程桌面怎么用(转)
  16. 2022华为机试真题 C++ 实现【九宫格按键输入法】
  17. 将电脑文件夹内的文件名批量导入到Excel表格中
  18. MIC的常见问题分析
  19. UDP服务器开发与nb-iot模组通信(1)----协议篇
  20. 【无标题】第一章:进入丰富多彩的计算机世界(一部分)

热门文章

  1. 不变的人生无常,变化的朋友来去
  2. 推荐一位字节大佬的刷题经验!
  3. Ubuntu拼音打不了中文
  4. 01、ZigBee 开发教程之进阶篇—BasicRF无线点对点传输协议
  5. 五年级春期计算机教案,五年级下册信息技术教案
  6. 【RDMA】使用‘无信号完成’(Working with Unsignaled completions)|IBV_SEND_SIGNALED
  7. Android API19 设置Alarm闹钟
  8. SAP S/4 HANA Cloud自定义报表制作方法二
  9. 树莓派之火焰传感器模块
  10. 使用echarts-gl 绘制3D地球配置详解