当需要分配的内存小于 Page 的时候,为了节约内存采用 PoolSubpage 实现小于 Page 大小内存的分配 。
在 PoolArena 中为了保证 PoolChunk 空间的最大利用化,按照 PoolArena 中各 个 PoolChunk 已使用的空间大小将其划分为六类:
- qInit:存储内存利用率 0-25% 的 chunk
- q000:存储内存利用率 1-50% 的 chunk
- q025:存储内存利用率 25-75% 的 chunk
- q050:存储内存利用率 50-100% 的 chunk
- q075:存储内存利用率 75-100%的 chunk
- q100:存储内存利用率 100%的 chunk
分配内存时,PoolArena 通过在 PoolChunkList 找到一个合适的 PoolChunk,然后从 PoolChunk 中分配一块内存 。
下面来看 PoolArena 是如何分配内存的:
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) { // 将需要申请的容量格式为 2^N final int normCapacity = normalizeCapacity(reqCapacity); // 判断目标容量是否小于8KB,小于8KB则使用tiny或small的方式申请内存 if (isTinyOrSmall(normCapacity)) { // capacity < pageSize int tableIdx; PoolSubpage<T>[] table; boolean tiny = isTiny(normCapacity); // 判断目标容量是否小于512字节,小于512字节的为tiny类型的 if (tiny) { // < 512 // 将分配区域转移到 tinySubpagePools 中 if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } // 如果无法从当前线程缓存中申请到内存,则尝试从tinySubpagePools中申请,这里tinyIdx()方法 // 就是计算目标内存是在tinySubpagePools数组中的第几号元素中的 tableIdx = tinyIdx(normCapacity); table = tinySubpagePools; } else { // 如果目标内存在512byte~8KB之间,则尝试从smallSubpagePools中申请内存 。这里首先从 // 当前线程的缓存中申请small级别的内存,如果申请到了,则直接返回 if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } tableIdx = smallIdx(normCapacity); table = smallSubpagePools; } // 获取目标元素的头结点 final PoolSubpage<T> head = table[tableIdx]; // 这里需要注意的是,由于对head进行了加锁,而在同步代码块中判断了s != head, // 也就是说PoolSubpage链表中是存在未使用的PoolSubpage的,因为如果该节点已经用完了, // 其是会被移除当前链表的 。也就是说只要s != head,那么这里的allocate()方法 // 就一定能够申请到所需要的内存块 synchronized (head) { // s != head就证明当前PoolSubpage链表中存在可用的PoolSubpage,并且一定能够申请到内存, // 因为已经耗尽的PoolSubpage是会从链表中移除的 final PoolSubpage<T> s = head.next; // 如果此时 subpage 已经被分配过内存了执行下文,如果只是初始化过,则跳过该分支 if (s != head) { // 从PoolSubpage中申请内存 assert s.doNotDestroy && s.elemSize == normCapacity; // 通过申请的内存对ByteBuf进行初始化 long handle = s.allocate(); assert handle >= 0; // 初始化 PoolByteBuf 说明其位置被分配到该区域,但此时尚未分配内存 s.chunk.initBufWithSubpage(buf, handle, reqCapacity); // 对tiny类型的申请数进行更新 if (tiny) { allocationsTiny.increment(); } else { allocationsSmall.increment(); } return; } } // 走到这里,说明目标PoolSubpage链表中无法申请到目标内存块,因而就尝试从PoolChunk中申请 allocateNormal(buf, reqCapacity, normCapacity); return; } // 走到这里说明目标内存是大于8KB的,那么就判断目标内存是否大于16M,如果大于16M, // 则不使用内存池对其进行管理,如果小于16M,则到PoolChunkList中进行内存申请 if (normCapacity <= chunkSize) { // 小于16M,首先到当前线程的缓存中申请,如果申请到了则直接返回,如果没有申请到, // 则到PoolChunkList中进行申请 if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) { // was able to allocate out of the cache so move on return; } allocateNormal(buf, reqCapacity, normCapacity); } else { // 对于大于16M的内存,Netty不会对其进行维护,而是直接申请,然后返回给用户使用 allocateHuge(buf, reqCapacity); }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 大学|高中生为什么要拼尽全力考入名校?这是我见到最好的答案
- 解冻淘宝店铺保证金需要把店铺商品下架吗 淘宝店被彻底释放了保证金怎么办?
- 生意参谋页面很多我想最快了解某一个指标 生意参谋商城点击占比在哪里
- 淘宝网店运营方案 淘宝运营方案策划
- 手机如何找回原来开的淘宝店铺 淘宝店铺被彻底释放后信誉还有吗
- 淘宝店铺推广方式 如何做淘宝推广
- 淘宝生意参谋怎么看同行转化率 阿里巴巴生意参谋怎么看同行数据
- 呈贡蒲门茶品鉴地,我们持盅看茶
- 怎么弄封别人的淘宝店 淘宝店铺被彻底释放了怎么办
- 淘宝卖家中心的体检中心在哪里 淘宝的体检中心在哪