PoolChunk 有如下三个属性,通过 prev 和 next 两个属性,形成一个双向 Chunk 链表 parent( PoolChunkList ):
/**
* 所属 PoolChunkList 对象
*/
PoolChunkList<T> parent;
/**
* 上一个 Chunk 对象
*/
PoolChunk<T> prev;
/**
* 下一个 Chunk 对象
*/
PoolChunk<T> next;
PoolChunkList ,实现 PoolChunkListMetric 接口,负责管理多个 Chunk 的生命周期,在此基础上对内存分配进行进一步的优化。
构造方法:
/**
* 所属 PoolArena 对象
*/
private final PoolArena<T> arena;
/**
* 下一个 PoolChunkList 对象
*/
private final PoolChunkList<T> nextList;
/**
* Chunk 最小内存使用率
*/
private final int minUsage;
/**
* Chunk 最大内存使用率
*/
private final int maxUsage;
/**
* 每个 Chunk 最大可分配的容量
*
* @see #calculateMaxCapacity(int, int) 方法
*/
private final int maxCapacity;
/**
* PoolChunk 头节点
*/
private PoolChunk<T> head;
/**
* 前一个 PoolChunkList 对象
*/
// This is only update once when create the linked like list of PoolChunkList in PoolArena constructor.
private PoolChunkList<T> prevList;
// TODO: Test if adding padding helps under contention
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) {
assert minUsage <= maxUsage;
this.arena = arena;
this.nextList = nextList;
this.minUsage = minUsage;
this.maxUsage = maxUsage;
// 计算 maxUsage 属性
maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
}
prevList 及 nextList ,上一个和下一个 PoolChunkList 对象。
所以,PoolChunkList 除了自身有一条双向链表外,PoolChunkList 和 PoolChunkList 之间也形成了一条双向链表。
minUsage 及 maxUsage ,PoolChunkList 管理的 Chunk 们的内存使用率。
当 Chunk 分配的内存率超过 maxUsage 时,从当前 PoolChunkList 节点移除,添加到下一个 PoolChunkList 节点( nextList );当 Chunk 分配的内存率小于 minUsage 时,从当前 PoolChunkList 节点移除,添加到上一个 PoolChunkList 节点( prevList )。
calculateMaxCapacity(int minUsage, int chunkSize) 方法,来计算每个 Chunk 最大可分配的容量:
/**
* Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s
* that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings.
*/
private static int calculateMaxCapacity(int minUsage, int chunkSize) {
// 计算 minUsage 值
minUsage = minUsage0(minUsage);
if (minUsage == 100) {
// If the minUsage is 100 we can not allocate anything out of this list.
return 0;
}
// Calculate the maximum amount of bytes that can be allocated from a PoolChunk in this PoolChunkList.
//
// As an example:
// - If a PoolChunkList has minUsage == 25 we are allowed to allocate at most 75% of the chunkSize because
// this is the maximum amount available in any PoolChunk in this PoolChunkList.
return (int) (chunkSize * (100L - minUsage) / 100L);
// Chunk 进入当前 PoolChunkList 节点,意味着 Chunk 内存已经分配了 minUsage 比率,所以 Chunk 剩余的容量是 chunkSize * (100L - minUsage) / 100L
}
// 保证最小 >= 1
private static int minUsage0(int value) {
return max(1, value);
}
allocate(PooledByteBuf buf, int reqCapacity, int normCapacity) 方法,给 PooledByteBuf 对象分配内存块,并返回是否分配内存块成功:
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
// 双向链表中无 Chunk
// 申请分配的内存超过 ChunkList 的每个 Chunk 最大可分配的容量,返回 false ,分配失败。
if (head == null || normCapacity > maxCapacity) {
// Either this PoolChunkList is empty or the requested capacity is larger then the capacity which can
// be handled by the PoolChunks that are contained in this PoolChunkList.
return false;
}
// 遍历双向链表。注意,遍历的是 ChunkList 的内部双向链表。
for (PoolChunk<T> cur = head;;) {
// 分配内存块
long handle = cur.allocate(normCapacity);
// 分配失败
if (handle < 0) {
// 进入下一节点
cur = cur.next;
// 若下一个节点不存在,返回 false ,结束循环
if (cur == null) {
return false; // 分配失败
}
// 分配成功
} else {
// 初始化内存块到 PooledByteBuf 对象中
cur.initBuf(buf, handle, reqCapacity);
// 超过当前 ChunkList 管理的 Chunk 的内存使用率上限
if (cur.usage() >= maxUsage) {
// 从当前 ChunkList 节点移除
remove(cur);
// 添加到下一个 ChunkList 节点
nextList.add(cur);
}
return true; // 分配成功
}
}
}
free(PoolChunk chunk, long handle) 方法,释放 PoolChunk 的指定位置( handle )的内存块:
boolean free(PoolChunk<T> chunk, long handle) {
// 释放 PoolChunk 的指定位置( handle )的内存块
chunk.free(handle);
// 小于当前 ChunkList 管理的 Chunk 的内存使用率下限
if (chunk.usage() < minUsage) {
// 从当前 ChunkList 节点移除
remove(chunk);
// 添加到上一个 ChunkList 节点
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
// 释放成功
return true;
}
接下来看看关于双向链表操作。
add(PoolChunk chunk) 方法,将 PoolChunk 添加到 ChunkList 节点中:
void add(PoolChunk<T> chunk) {
// 超过当前 ChunkList 管理的 Chunk 的内存使用率上限,继续递归到下一个 ChunkList 节点进行添加。
if (chunk.usage() >= maxUsage) {
nextList.add(chunk);
return;
}
// 执行真正的添加
add0(chunk);
}
add0(PoolChunk chunk) 方法,执行真正的添加:
/**
* Adds the {@link PoolChunk} to this {@link PoolChunkList}.
*/
void add0(PoolChunk<T> chunk) {
chunk.parent = this;
// 无头节点,自己成为头节点
if (head == null) {
head = chunk;
chunk.prev = null;
chunk.next = null;
// 有头节点,自己成为头节点,原头节点成为自己的下一个节点
// 因为 chunk 新进入下一个 ChunkList 节点,一般来说,内存使用率相对较低,分配内存块成功率相对较高,所以变成新的首节点。
} else {
chunk.prev = null;
chunk.next = head;
head.prev = chunk;
head = chunk;
}
}
remove(PoolChunk chunk) 方法,从当前 ChunkList 节点移除:
private void remove(PoolChunk<T> cur) {
// 当前节点为首节点,将下一个节点设置为头节点
if (cur == head) {
head = cur.next;
if (head != null) {
head.prev = null;
}
// 当前节点非首节点,将节点的上一个节点指向节点的下一个节点
} else {
PoolChunk<T> next = cur.next;
cur.prev.next = next;
if (next != null) {
next.prev = cur.prev;
}
}
}
move(PoolChunk chunk) 方法, 添加到“上”一个 ChunkList 节点:
/**
* Moves the {@link PoolChunk} down the {@link PoolChunkList} linked-list so it will end up in the right
* {@link PoolChunkList} that has the correct minUsage / maxUsage in respect to {@link PoolChunk#usage()}.
*/
private boolean move(PoolChunk<T> chunk) {
assert chunk.usage() < maxUsage;
// 小于当前 ChunkList 管理的 Chunk 的内存使用率下限,继续递归到上一个 ChunkList 节点进行添加。
if (chunk.usage() < minUsage) {
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
// 执行真正的添加
// PoolChunk fits into this PoolChunkList, adding it here.
add0(chunk);
return true;
}
当小于当前 ChunkList 管理的 Chunk 的内存使用率下限,调用move0(PoolChunk chunk) 方法,继续递归到上一个 ChunkList 节点进行添加:
private boolean move(PoolChunk<T> chunk) {
assert chunk.usage() < maxUsage;
// 小于当前 ChunkList 管理的 Chunk 的内存使用率下限,继续递归到上一个 ChunkList 节点进行添加。
if (chunk.usage() < minUsage) {
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
// 执行真正的添加
// PoolChunk fits into this PoolChunkList, adding it here.
add0(chunk);
return true;
}
iterator() 方法,创建 Iterator 对象:
private static final Iterator<PoolChunkMetric> EMPTY_METRICS = Collections.<PoolChunkMetric>emptyList().iterator();
@Override
public Iterator<PoolChunkMetric> iterator() {
synchronized (arena) {
// 空,返回 EMPTY_METRICS
if (head == null) {
return EMPTY_METRICS;
}
// 生成数组,后生成 Iterator
List<PoolChunkMetric> metrics = new ArrayList<PoolChunkMetric>();
for (PoolChunk<T> cur = head;;) {
metrics.add(cur);
cur = cur.next;
if (cur == null) {
break;
}
}
return metrics.iterator();
}
}
destroy() 方法,销毁:
void destroy(PoolArena<T> arena) {
// 循环,销毁 ChunkList 管理的所有 Chunk
PoolChunk<T> chunk = head;
while (chunk != null) {
arena.destroyChunk(chunk);
chunk = chunk.next;
}
// 置空
head = null;
}
PoolChunkListMetric ,继承 Iterable 接口,PoolChunkList Metric 接口:
public interface PoolChunkListMetric extends Iterable<PoolChunkMetric> {
/**
* Return the minimum usage of the chunk list before which chunks are promoted to the previous list.
*/
int minUsage();
/**
* Return the maximum usage of the chunk list after which chunks are promoted to the next list.
*/
int maxUsage();
}
PoolChunkList 对 PoolChunkMetric 接口的实现:
@Override
public int minUsage() {
return minUsage0(minUsage);
}
@Override
public int maxUsage() {
return min(maxUsage, 100);
}