Netty学习之旅----源码分析内存分配与释放原理,卑微打工人

本文深入剖析Netty的内存管理机制,详细讲解PoolChunk和PoolArena的内存分配与释放过程,包括allocateRun、allocateHuge方法的实现,以及PoolSubpage的内存回收。通过源码分析,揭示Netty如何高效管理内存,特别是超过pageSize的大内存分配和释放策略。
摘要由CSDN通过智能技术生成

private long toHandle(int bitmapIdx) {

return 0xb000000000000000L | (long) bitmapIdx << 32 | memoryMapIdx;

}

该值,主要是用一个long类型的值的低32位来表示 memoryMapIdx,用高32位表示 bitmapIdx,这里为什么需要与0xb000000000000000L进行或运算呢?据我的目前掌握的知识看,主要是将0映射为一个数字,主要来区分是在PoolSubpage中分配的,还是内存大于pageSize,在内存释放的时候,可以通过bitmaIdx >> 32 & 0x3FFFFFFF 得出原来的索引。

1.3.1.4 关于 PoolArena allocate代码@4 initBuf详解:

void initBuf(PooledByteBuf buf, long handle, int reqCapacity) {

int memoryMapIdx = (int) handle;//@1

int bitmapIdx = (int) (handle >>> Integer.SIZE); //@2

if (bitmapIdx == 0) {//@3

byte val = value(memoryMapIdx);

assert val == unusable : String.valueOf(val);

buf.init(this, handle, runOffset(memoryMapIdx), reqCapacity, runLength(memoryMapIdx));

} else {//@4

initBufWithSubpage(buf, handle, bitmapIdx, reqCapacity);

}

}

首先这里对入参 long handle做一个详解:如果需要分配的内存大于pageSize,则返回的高32为为0,低32位为memoryMap的下标id。具体参照下文的allocateRun方法讲解;如果需要分配的内存小于pageSize,则返回的高32为为bitmapIdx,低32位同样表示memoryMap的id。

代码@1:从long中获取memoryMapIdx。

代码@2:从long中获取bitmapIdx。

代码@3:如果bitmapIdx为0,偏移量就是PoolSubpage的偏移量。为什么呢?bitmapIdx为0在内存申请大于pageSize和小于pageSize时都会出现:

  • 如果申请的内存数小于pageSize,bitmapIdx表示该pageSubpage是第一次分配。

  • 如果申请的内存数大于pageSize,表明该节点所以子节点都是第一次被分片。故偏移量就是memory[id]所代表的偏移量。

代码@4:如果bitmapIdx不为0,需要计算偏移量,与PoolSubpage的elemSize相关,具体请看2)PoolChunk的initBufWithSubpage方法,该方法,最终还是要调用PooledByteBuf的init方法,分配内存,这里只是需要计算偏远量。

1、PooledByteBuf的 int方法

void init(PoolChunk chunk, long handle, int offset, int length, int maxLength) {

assert handle >= 0;

assert chunk != null;

this.chunk = chunk;

this.handle = handle;

memory = chunk.memory; // @1

this.offset = offset; // @2

this.length = length; // @3

this.maxLength = maxLength; // @4

setIndex(0, 0); //@5

tmpNioBuf = null;

initThread = Thread.currentThread();//@6

}

代码@1:PooledByteBuf的内存,直接指向PoolChunk的memory;

代码@2:offset,在memory的起始偏移量。

代码@3:memory的offset + length之间的内存被该PooledByteBuf占用,其他ByteBuf无法使用。

代码@4:maxLength的作用是什么呢?目前我的理解是,PooledByteBuf自动扩容时,只要最终长度不超过maxLength,就可以在当前的内存中完成,不需要去申请新的空间,再进行内存负责。

代码@5:初始化readIndex,writeIndex。

代码@6:记录该PooledByteBuf的初始化线程,方便本地线程池的使用。

2、PoolChunk的iinitBufWithSubpage方法详解

private void initBufWithSubpage(PooledByteBuf buf, long handle, int bitmapIdx, int reqCapacity) {

assert bitmapIdx != 0;

int memoryMapIdx = (int) handle;

PoolSubpage subpage = subpages[subpageIdx(memoryMapIdx)];

assert subpage.doNotDestroy;

assert reqCapacity <= subpage.elemSize;

buf.init(

this, handle,

runOffset(memoryMapIdx) + (bitmapIdx & 0x3FFFFFFF) * subpage.elemSize, reqCapacity, subpage.elemSize);

}

1.3.2 PoolChunk allocate关于代码@allocateRun,超过pageSize内存分配源码分析

/**

  • Allocate a run of pages (>=1)

  • @param normCapacity normalized capacity

  • @return index in memoryMap

*/

private long allocateRun(int normCapacity) {

int d = maxOrder - (log2(normCapacity) - pageShifts); //@1

int id = allocateNode(d); //@2

if (id < 0) {

return id;

}

freeBytes -= runLength(id); //@3

return id;

}

该方法的实现,就是要在平衡二叉树中要找到一个可以满足normCapacity的节点,从前文的介绍中得知,memoryMap[id]存放的是,该id能分配的最小深度代表的容量。超过pageSize的内存节点,肯定不是在叶子节点。如果让我实现查找合适id的算法,我想应该是这样的:

1、算成需要分配的内存大小是 pag

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值