Netty源码分析:PoolArena
Arena本身是指一块区域,在内存管理中,Memory Arena是指内存中的一大块连续的区域,PoolArena就是Netty的内存池实现类。
Netty的PoolArena是由多个Chunk组成的大块内存区域,而每个Chunk则由一个或者多个Page组成(在博文Netty源码分析:PoolChunk已经明确了这点),因此,对内存的组织和管理也就主要集中在如何管理和组织Chunk和Page了。
先说结论:PoolArena通过6个PoolChunkList来管理PoolChunk,而每个PoolChunk由N个PoolSubpage构成,即将PoolChunk的里面底层实现 T memory分成N段,每段就是一个PoolSubpage。当用户申请一个Buf时,使用Arena所拥有的chunk所管辖的page分配内存,内存分配的落地点为 T memory上。
看一个例子
假设每个Page的大小为8192。在下面的代码中就是申请两块buf。所得到的结果就是:byteBuf将利用PoolChunk的第0个PoolSubpage进行分配,分配的buf的内存为:从memory[0]开始且长度为15最大长度为16;byteBuf1将利用PoolChunk的第1个PoolSubpage进行分配,分配的落地点从memory[8192]开始且长度为17最大长度为32的内存.
截图如下:
public class TestByteBuf {
public static void main(String[] args) {
//1 分配一个ByteBuf,然后写入数据到此Buf
PooledByteBufAllocator allocator = new PooledByteBufAllocator(false);
ByteBuf byteBuf = allocator.heapBuffer(15);
ByteBuf byteBuf1 = allocator.heapBuffer(17);
String content = "wojiushimogui";
byteBuf.writeBytes(content.getBytes());
System.out.println("1、readerIndex:"+byteBuf.readerIndex());
System.out.println("1、writerIndex:"+byteBuf.writerIndex());
}
}
本文将从源码的角度主要介绍下PoolArena。
1、属性
abstract class PoolArena<T> {
static final int numTinySubpagePools = 512 >>> 4;
final PooledByteBufAllocator parent;//表示该PoolArena的allocator
private final int maxOrder;//表示chunk中由Page节点构成的二叉树的最大高度。默认11
final int pageSize;//page的大小,默认8K
final int pageShifts;//pageShifts=log(pageSize),默认13
final int chunkSize;//chunk的大小
final int subpageOverflowMask;//该变量用于判断申请的内存大小与page之间的关系,是大于,还是小于
final int numSmallSubpagePools;//用来分配small内存的数组长度
/*
tinySubpagePools来缓存(或说是存储)用来分配tiny(小于512)内存的Page;
smallSubpagePools来缓存用来分配small(大于等于512且小于pageSize)内存的Page
*/
private final PoolSubpage<T>[] tinySubpagePools;
private final PoolSubpage<T>[] smallSubpagePools;
//用来存储用来分配给Normal(超过一页)大小内存的PoolChunk。
private final PoolChunkList<T> q050;
private final PoolChunkList<T> q025;
private final PoolChunkList<T> q000;
private final PoolChunkList<T> qInit;
private final PoolChunkList<T> q075;
private final PoolChunkList<T> q100;
PoolArena属性的各个含义已在代码中进行了解释哈。下面来看构造函数。
2、构造函数
构造函数的代码如下:
protected PoolArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) {
//从PooledByteBufAllocator中传送过来的相关字段值。
this.parent = parent;
this.pageSize = pageSize;
this.maxOrder = maxOrder;
this.pageShifts = pageShifts;
this.chunkSize = chunkSize;
subpageOverflowMask = ~(pageSize - 1);//该变量用于判断申请的内存大小与page之间的关系,是大于,还是小于
tinySubpagePools = newSubpagePoolArray(numTinySubpagePools);
for (int i = 0; i < tinySubpagePools.length; i ++) {
tinySubpagePools[i] = newSubpagePoolHead(pageSize);
}
numSmallSubpagePools = pageShifts - 9;
smallSubpagePools = newSubpagePoolArray(numSmallSubpagePools);
for (int i = 0; i < smallSubpagePools.length; i ++) {
smallSubpagePools[i] = newSubpagePoolHead(pageSize);
}
q100 = new PoolChunkList<T>(this, null, 100, Integer.MAX_VALUE);
q075 = new PoolChunkList<T>(this, q100, 75, 100);
q050 = new PoolChunkList<T>(this, q075, 50, 100);
q025 = new PoolChu