概要
在Netty中, PoolArena將內(nèi)存分為很多PoolChunk進行管理. 通過多個PoolChunkList根據(jù)PoolChunk的使用率進行分組保存唠粥,并將動態(tài)的移動至對應的PoolChunkList中
在PoolArena中根據(jù)使用率分如下幾組PoolChunkList
private final PoolChunkList<T> q050; //存儲內(nèi)存利用率50-100%的PoolChunk
private final PoolChunkList<T> q025; //存儲內(nèi)存利用率25-75%的PoolChunk
private final PoolChunkList<T> q000; //存儲內(nèi)存利用率1-50%的PoolChunk
private final PoolChunkList<T> qInit; //存儲內(nèi)存利用率0-25%的PoolChunk
private final PoolChunkList<T> q075; //存儲內(nèi)存利用率75-100%的PoolChunk
private final PoolChunkList<T> q100; //存儲內(nèi)存利用率100%的PoolChunk
q100 = new PoolChunkList<T>(null, 100, Integer.MAX_VALUE, chunkSize);
q075 = new PoolChunkList<T>(q100, 75, 100, chunkSize);
q050 = new PoolChunkList<T>(q075, 50, 100, chunkSize);
q025 = new PoolChunkList<T>(q050, 25, 75, chunkSize);
q000 = new PoolChunkList<T>(q025, 1, 50, chunkSize);
qInit = new PoolChunkList<T>(q000, Integer.MIN_VALUE, 25, chunkSize);
q100.prevList(q075);
q075.prevList(q050);
q050.prevList(q025);
q025.prevList(q000);
q000.prevList(null);
qInit.prevList(qInit);
img
PoolChunkList類主要屬性如下所示:
// 下一個ChunkList
private final PoolChunkList<T> nextList;
// 最小內(nèi)存使用率
private final int minUsage;
// 最大內(nèi)存使用率
private final int maxUsage;
private final int maxCapacity;
// 頭節(jié)點
private PoolChunk<T> head;
// 上一個ChunkList
private PoolChunkList<T> prevList;
img
構(gòu)造方法
PoolChunkList(PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) {
assert minUsage <= maxUsage;
this.nextList = nextList;
this.minUsage = minUsage;
this.maxUsage = maxUsage;
// 該list所能分配的最大容量
maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
}
private static int calculateMaxCapacity(int minUsage, int chunkSize) {
minUsage = minUsage0(minUsage);
if (minUsage == 100) {
return 0;
}
// 計算一個chunk在除去最小的使用率的情況下所能分配的最大空間
// Q25的maxCapacity=chunkSize*75%
return (int) (chunkSize * (100L - minUsage) / 100L);
}
添加
void add(PoolChunk<T> chunk) {
// 看當前chunk的使用率是否超過了最大值, 加到下一個list
if (chunk.usage() >= maxUsage) {
nextList.add(chunk);
return;
}
add0(chunk);
}
void add0(PoolChunk<T> chunk) {
// 在chunk中保存所屬的chunlist
chunk.parent = this;
// 如果還沒有head, chunk來
if (head == null) {
head = chunk;
chunk.prev = null;
chunk.next = null;
} else {
// 將這個chunk加到list里面作為新的head
chunk.prev = null;
chunk.next = head;
head.prev = chunk;
head = chunk;
}
}
刪除
private void remove(PoolChunk<T> cur) {
if (cur == head) {
// 讓下一個接替head
head = cur.next;
if (head != null) {
head.prev = null;
}
} else {
// 將cur前后解綁
PoolChunk<T> next = cur.next;
cur.prev.next = next;
if (next != null) {
next.prev = cur.prev;
}
}
}
分配
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
// 如果沒有head或超過最大容量,那么返回false,表示分配失敗
if (head == null || normCapacity > maxCapacity) {
return false;
}
// 遍歷chunklist
for (PoolChunk<T> cur = head;;) {
// 去chunk中申請空間
long handle = cur.allocate(normCapacity);
// 如果handle<0, 說明申請失敗, 繼續(xù)滾動到下一個chunk循環(huán)
if (handle < 0) {
cur = cur.next;
if (cur == null) {
return false;
}
} else {
// 如果申請成功, 那么將內(nèi)存空間與ByteBuf進行綁定
cur.initBuf(buf, handle, reqCapacity);
// 接著計算當前chunk的使用率,如果超過最大閾值,那么從當前l(fā)ist中刪除,并移動到下個list
// 也就是升艙處理
if (cur.usage() >= maxUsage) {
remove(cur);
nextList.add(cur);
}
return true;
}
}
}
釋放
boolean free(PoolChunk<T> chunk, long handle) {
// 釋放該chunk對應的handle持有的內(nèi)存空間
chunk.free(handle);
// 如果小于最下,那么同理需要降級處理
if (chunk.usage() < minUsage) {
remove(chunk);
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
return true;
}
移動
private boolean move0(PoolChunk<T> chunk) {
if (prevList == null) {
assert chunk.usage() == 0;
return false;
}
return prevList.move(chunk);
}
private boolean move(PoolChunk<T> chunk) {
// 接著move0的上下文,這里已經(jīng)到了prevlist, 判斷是否滿足該list的使用率條件
assert chunk.usage() < maxUsage;
// 如果還是低于該區(qū)的最小,那么繼續(xù)降級
if (chunk.usage() < minUsage) {
return move0(chunk);
}
// 否則add到該list
add0(chunk);
return true;
}