深入淺出Netty內存管理:PoolChunkList
本文主要分析管理PoolChunk生命周期的PoolChunkList。
PoolChunkList
PoolChunkList負責管理多個chunk的生命周期,在此基礎上對內存分配進行進一步的優化。
final class PoolChunkList<T> implements PoolChunkListMetric {
private final PoolChunkList<T> nextList;
private final int minUsage;
private final int maxUsage;
private PoolChunk<T> head;
private PoolChunkList<T> prevList;
...
}
從代碼實現可以看出,每個PoolChunkList實例維護了一個PoolChunk鏈表,自身也形成一個鏈表,為何要這么實現?
隨著chunk中page的不斷分配和釋放,會導致很多碎片內存段,大大增加了之后分配一段連續內存的失敗率,針對這種情況,可以把內存使用率較大的chunk放到PoolChunkList鏈表更后面,具體實現如下:
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
if (head == null) {
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);
if (cur.usage() >= maxUsage) { // (1)
remove(cur);
nextList.add(cur);
}
return true;
}
}
}
假設poolChunkList中已經存在多個chunk。當分配完內存后,如果當前chunk的使用量超過maxUsage,則把該chunk從當前鏈表中刪除,添加到下一個鏈表中。
但是,隨便chunk中內存的釋放,其內存使用率也會隨著下降,當下降到minUsage時,該chunk會移動到前一個列表中,實現如下:
boolean free(PoolChunk<T> chunk, long handle) {
chunk.free(handle);
if (chunk.usage() < minUsage) {
remove(chunk);
if (prevList == null) {
assert chunk.usage() == 0;
return false;
} else {
prevList.add(chunk);
return true;
}
}
return true;
}
從poolChunkList的實現可以看出,每個chunkList的都有一個上下限:minUsage和maxUsage,兩個相鄰的chunkList,前一個的maxUsage和后一個的minUsage必須有一段交叉值進行緩沖,否則會出現某個chunk的usage處于臨界值,而導致不停的在兩個chunk間移動。
所以chunk的生命周期不會固定在某個chunkList中,隨著內存的分配和釋放,根據當前的內存使用率,在chunkList鏈表中前后移動。
來自:http://blog.jobbole.com/106085/
本文由用戶 JosMLXB 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!