概述(Motivation)
chunklist
实现细节(Modification)
主要成员
private final PoolArena<T> arena;
private final PoolChunkList<T> nextList;
private final int minUsage;
private final int maxUsage;
// poolChunkList存放的都是同一种chunk,所以初始化的时候根据chunkSize*(1-minUsage)
// 因为此List中的chunk使用率最低是minUsage,所以最多只能分配(1-minUsage)
private final int maxCapacity;
private PoolChunk<T> head;
// This is only update once when create the linked like list of PoolChunkList in PoolArena constructor.
private PoolChunkList<T> prevList;
分配函数
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
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;
}
for (PoolChunk<T> cur = head;;) {
long handle = cur.allocate(normCapacity);
if (handle < 0) {
cur = cur.next;
if (cur == null) {
return false;
}
} else {
// 分配成功
cur.initBuf(buf, handle, reqCapacity);
// 超过使用率会将chunk转移到下一个list
if (cur.usage() >= maxUsage) {
remove(cur);
nextList.add(cur);
}
return true;
}
}
}
释放函数
boolean free(PoolChunk<T> chunk, long handle) {
chunk.free(handle);
// 如果释放后当前使用量低于限定值,移动到前一个
if (chunk.usage() < minUsage) {
// chunkList自身指针的操作去除该chunk结点
remove(chunk);
// Move the PoolChunk down the PoolChunkList linked-list.
// 该chunk进行移动
return move0(chunk);
}
return true;
}
/**
* 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 move0(PoolChunk<T> chunk) {
if (prevList == null) {
// There is no previous PoolChunkList so return false which result in having the PoolChunk destroyed and
// all memory associated with the PoolChunk will be released.
// 调用者的逻辑会将该chunk进行destroy处理
assert chunk.usage() == 0;
return false;
}
return prevList.move(chunk);
}
private boolean move(PoolChunk<T> chunk) {
assert chunk.usage() < maxUsage;
if (chunk.usage() < minUsage) {
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
// PoolChunk fits into this PoolChunkList, adding it here.
// chunkList自身指针的操作加入该chunk结点
add0(chunk);
return true;
}
分配顺序
之前在poolArena
中,分配的顺序是50->25->00->init->75。
网上基本就一个观点。。高峰期分配内存容易释放掉不会堆积。
我觉得一个网络一般是稳定,那么意味着我们希望保持一个高使用率的内存,避免浪费,所以从50起是一个适中值堆积起一些常用的内存。当然50确实是个适中值,基本上所有情况下你都可以说中位数是一个合理值。。
综述(Result)
一个描述使用率的链表,将不同使用率的chunk分开,从而能更合理的分配和释放内存。