前面我們說到了Netty的內存管理機制根竿,也討論了PoolChunk的內存分配算法,但是PoolChunk只有16M在跳,這遠遠不夠用荞下,所以會有很多很多PoolChunk伶选,這些PoolChunk組成一個鏈表,然后用PoolChunkList持有這個鏈表尖昏。下面就來介紹一下PoolChunkList仰税。
先看一下PoolChunkList有哪些屬性
/**
* 所屬 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 頭節(jié)點
*/
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;
PoolChunkList包含了一個prev和一個next,組成了一個鏈表。既然按使用率分配抽诉,那么PoolChunk在使用過程中是會動態(tài)變化的陨簇,所以PoolChunk會在不同PoolChunkList中變化。同時申請空間迹淌,使用哪一個PoolChunkList也是有先后順序的河绽。下面我們來看看PoolChunkList是怎么分配內存的。
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
// 雙向鏈表中無 Chunk
// 申請分配的內存超過 ChunkList 的每個 Chunk 最大可分配的容量
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) {
// 進入下一節(jié)點
cur = cur.next;
// 若下一個節(jié)點不存在纹份,返回 false 苟跪,結束循環(huán)
if (cur == null) {
return false; // 分配失敗
}
// 分配成功
} else {
// 初始化內存塊到 PooledByteBuf 對象中
cur.initBuf(buf, handle, reqCapacity);
// 超過當前 ChunkList 管理的 Chunk 的內存使用率上限
if (cur.usage() >= maxUsage) {
// 從當前 ChunkList 節(jié)點移除
remove(cur);
// 添加到下一個 ChunkList 節(jié)點
nextList.add(cur);
}
return true; // 分配成功
}
}
}
PoolChunkList的分析就到這里了。