在PoolChunk类中会持有一个PoolChunkList对象,本篇解析一下PoolChunkList的功能。

PoolChunkList

PoolChunkList类内部持有一个chunk链表,PoolChunkList本身也是链表结构。PoolChunkList功能是通过使用率来管理chunk。

PoolChunkList链表在分配内存和释放内存的过程中会调节chunk的位置:如果chunk的使用率低于最小使用率则会将chunk节点迁移到前面。保证低使用率的节点在前。

继承关系及成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final class PoolChunkList<T> implements PoolChunkListMetric {
private static final Iterator<PoolChunkMetric> EMPTY_METRICS = Collections.<PoolChunkMetric>emptyList().iterator();
// arena对象,由arena管理
private final PoolArena<T> arena;
// 下一个节点,链表结构
private final PoolChunkList<T> nextList;
// 最小使用率
private final int minUsage;
// 最大使用率
private final int maxUsage;
// 最大容量
private final int maxCapacity;
// chunk链表
private PoolChunk<T> head;
// 链表头,只会设置一次(在PoolArena构造器初始化PoolChunkList的时候)
// This is only update once when create the linked like list of PoolChunkList in PoolArena constructor.
private PoolChunkList<T> prevList;
}

构造器

1
2
3
4
5
6
7
8
9
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;
// 最大容量 chunkSize * (1 - 最小使用率)
maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
}

计算最大容量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static int calculateMaxCapacity(int minUsage, int chunkSize) {
// 1和minUsage取最大值
minUsage = minUsage0(minUsage);
// 最小使用率为100,则直接返回0
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.
// 最大使用量是chunkSize * (1 - 最小使用率)
return (int) (chunkSize * (100L - minUsage) / 100L);
}
private static int minUsage0(int value) {
return max(1, value);
}

内存分配allocate

PoolChunkList中存有一个PoolChunk链表(PoolChunk head),PoolChunkList分配内存就是遍历这链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
// 容量不够
if (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;
}
// 变量head链表,调用PoolChunk的allocate方法分配内存
for (PoolChunk<T> cur = head; cur != null; cur = cur.next) {
if (cur.allocate(buf, reqCapacity, normCapacity)) {
// 如果chunk的使用率大于设定最大使用率则将该chunk节点移出链表,存到下一个PoolChunkList的链表中
if (cur.usage() >= maxUsage) {
remove(cur);
// 存到next的链表中
nextList.add(cur);
}
return true;
}
}
return false;
}

  1. 容量不够则返回false;
  2. 遍历chunk链表:
    1. 如果执行chunk的allocate分配成功:
      1. 如果chunk的使用率大于设定最大使用率:
        1. 将chunk节点移出当前chunkList的链表;
        2. 将chunk节点添加到nextList的链表中(这个添加时个递归过程,最终是添加到chunk.usage() < maxUsage的chunkList中);

内存释放free

1
2
3
4
5
6
7
8
9
boolean free(PoolChunk<T> chunk, long handle, ByteBuffer nioBuffer) {
chunk.free(handle, nioBuffer);
if (chunk.usage() < minUsage) {
remove(chunk);
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
return true;
}
  1. 执行chunk的free方法释放内存;
  2. 如果chunk的使用率小于最小使用率则将其移出prevList的链表

remove

将cur节点从chunk链表中移除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}
}
}

chunk移动move

chunkList的move和add有个特点:会根据使用率调整chunk的位置

move如果chunk.usage() < minUsage会将chunk移到最前面;

1
2
3
4
5
6
7
8
9
10
11
private boolean move(PoolChunk<T> chunk) {
assert chunk.usage() < maxUsage;
// 如果使用率低于最小使用率则将chunk移出链表
if (chunk.usage() < minUsage) {
// Move the PoolChunk down the PoolChunkList linked-list.
return move0(chunk);
}
// 使用率大于等于最小使用率
add0(chunk);
return true;
}
  1. 如果使用率低于最小使用率,则将chunk移出prevList的链表;
  2. 使用率大于等于最小使用率,则将其添加到当前chunkList。

move0:将chunk从prevList中移除。

1
2
3
4
5
6
7
8
9
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.
assert chunk.usage() == 0;
return false;
}
return prevList.move(chunk);
}

chunk添加add

add方法如果出现chunk的使用率大于当前chunkList的最大使用率会将chunk添加到一个chunk.usage() < maxUsage的chunkList中

1
2
3
4
5
6
7
void add(PoolChunk<T> chunk) {
if (chunk.usage() >= maxUsage) {
nextList.add(chunk);
return;
}
add0(chunk);
}

  1. 如果chunk使用率大于最大使用率,则将其添加到nextList节点;
  2. 不然执行add0,将其添加到当前chunkList的链表中。
1
2
3
4
5
6
7
8
9
10
11
12
13
void add0(PoolChunk<T> chunk) {
chunk.parent = this;
if (head == null) {
head = chunk;
chunk.prev = null;
chunk.next = null;
} else {
chunk.prev = null;
chunk.next = head;
head.prev = chunk;
head = chunk;
}
}