Netty之Jemalloc(三)PoolChunkList

PoolChunk 有如下三个属性,通过 prev 和 next 两个属性,形成一个双向 Chunk 链表 parent( PoolChunkList ):

/**
 * 所属 PoolChunkList 对象
 */
PoolChunkList<T> parent;
/**
 * 上一个 Chunk 对象
 */
PoolChunk<T> prev;
/**
 * 下一个 Chunk 对象
 */
PoolChunk<T> next;

PoolChunkList ,实现 PoolChunkListMetric 接口,负责管理多个 Chunk 的生命周期,在此基础上对内存分配进行进一步的优化。
构造方法:

/**
 * 所属 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 头节点
 */
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;

// TODO: Test if adding padding helps under contention
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;

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;
    // 计算 maxUsage 属性
    maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
}

prevList 及 nextList ,上一个和下一个 PoolChunkList 对象。
所以,PoolChunkList 除了自身有一条双向链表外,PoolChunkList 和 PoolChunkList 之间也形成了一条双向链表。
minUsage 及 maxUsage ,PoolChunkList 管理的 Chunk 们的内存使用率。
当 Chunk 分配的内存率超过 maxUsage 时,从当前 PoolChunkList 节点移除,添加到下一个 PoolChunkList 节点( nextList );当 Chunk 分配的内存率小于 minUsage 时,从当前 PoolChunkList 节点移除,添加到上一个 PoolChunkList 节点( prevList )。

calculateMaxCapacity(int minUsage, int chunkSize) 方法,来计算每个 Chunk 最大可分配的容量:

/**
 * Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s
 * that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings.
 */
private static int calculateMaxCapacity(int minUsage, int chunkSize) {
    // 计算 minUsage 值
    minUsage = minUsage0(minUsage);

    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.
    return  (int) (chunkSize * (100L - minUsage) / 100L);
// Chunk 进入当前 PoolChunkList 节点,意味着 Chunk 内存已经分配了 minUsage 比率,所以 Chunk 剩余的容量是 chunkSize * (100L - minUsage) / 100L 
}

// 保证最小 >= 1
private static int minUsage0(int value) {
    return max(1, value);
}

allocate(PooledByteBuf buf, int reqCapacity, int normCapacity) 方法,给 PooledByteBuf 对象分配内存块,并返回是否分配内存块成功:

 boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
     // 双向链表中无 Chunk
     // 申请分配的内存超过 ChunkList 的每个 Chunk 最大可分配的容量,返回 false ,分配失败。
     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) {
             // 进入下一节点
             cur = cur.next;
             // 若下一个节点不存在,返回 false ,结束循环
             if (cur == null) {
                 return false; // 分配失败
             }
         // 分配成功
         } else {
             // 初始化内存块到 PooledByteBuf 对象中
             cur.initBuf(buf, handle, reqCapacity);
             // 超过当前 ChunkList 管理的 Chunk 的内存使用率上限
             if (cur.usage() >= maxUsage) {
                 // 从当前 ChunkList 节点移除
                 remove(cur);
                 // 添加到下一个 ChunkList 节点
                 nextList.add(cur); 
             }
             return true; // 分配成功
         }
     }
 }

free(PoolChunk chunk, long handle) 方法,释放 PoolChunk 的指定位置( handle )的内存块:

 boolean free(PoolChunk<T> chunk, long handle) {
     // 释放 PoolChunk 的指定位置( handle )的内存块
     chunk.free(handle);
     // 小于当前 ChunkList 管理的 Chunk 的内存使用率下限
     if (chunk.usage() < minUsage) {
         // 从当前 ChunkList 节点移除
         remove(chunk);
         // 添加到上一个 ChunkList 节点
         // Move the PoolChunk down the PoolChunkList linked-list.
         return move0(chunk);
     }
     // 释放成功
     return true;
 }

接下来看看关于双向链表操作。
add(PoolChunk chunk) 方法,将 PoolChunk 添加到 ChunkList 节点中:

void add(PoolChunk<T> chunk) {
    // 超过当前 ChunkList 管理的 Chunk 的内存使用率上限,继续递归到下一个 ChunkList 节点进行添加。
     if (chunk.usage() >= maxUsage) {
        nextList.add(chunk);
        return;
    }
    // 执行真正的添加
    add0(chunk);
}

add0(PoolChunk chunk) 方法,执行真正的添加:

/**
 * Adds the {@link PoolChunk} to this {@link PoolChunkList}.
 */
void add0(PoolChunk<T> chunk) {
    chunk.parent = this;
    // 无头节点,自己成为头节点
    if (head == null) {
        head = chunk;
        chunk.prev = null;
        chunk.next = null;
    // 有头节点,自己成为头节点,原头节点成为自己的下一个节点
    // 因为 chunk 新进入下一个 ChunkList 节点,一般来说,内存使用率相对较低,分配内存块成功率相对较高,所以变成新的首节点。
    } else {
        chunk.prev = null;
        chunk.next = head;
        head.prev = chunk;
        head = chunk;
    }
}

remove(PoolChunk chunk) 方法,从当前 ChunkList 节点移除:

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;
        }
    }
}

move(PoolChunk chunk) 方法, 添加到“上”一个 ChunkList 节点:

   /**
    * 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 move(PoolChunk<T> chunk) {
     assert chunk.usage() < maxUsage;
 
     // 小于当前 ChunkList 管理的 Chunk 的内存使用率下限,继续递归到上一个 ChunkList 节点进行添加。
     if (chunk.usage() < minUsage) {
         // Move the PoolChunk down the PoolChunkList linked-list.
         return move0(chunk);
     }
 
     // 执行真正的添加
     // PoolChunk fits into this PoolChunkList, adding it here.
     add0(chunk);
     return true;
 }

当小于当前 ChunkList 管理的 Chunk 的内存使用率下限,调用move0(PoolChunk chunk) 方法,继续递归到上一个 ChunkList 节点进行添加:

private boolean move(PoolChunk<T> chunk) {
    assert chunk.usage() < maxUsage;

    // 小于当前 ChunkList 管理的 Chunk 的内存使用率下限,继续递归到上一个 ChunkList 节点进行添加。
    if (chunk.usage() < minUsage) {
        // Move the PoolChunk down the PoolChunkList linked-list.
        return move0(chunk);
    }

    // 执行真正的添加
    // PoolChunk fits into this PoolChunkList, adding it here.
    add0(chunk);
    return true;
}

iterator() 方法,创建 Iterator 对象:

private static final Iterator<PoolChunkMetric> EMPTY_METRICS = Collections.<PoolChunkMetric>emptyList().iterator();

@Override
public Iterator<PoolChunkMetric> iterator() {
    synchronized (arena) {
        // 空,返回 EMPTY_METRICS
        if (head == null) {
            return EMPTY_METRICS;
        }
        // 生成数组,后生成 Iterator
        List<PoolChunkMetric> metrics = new ArrayList<PoolChunkMetric>();
        for (PoolChunk<T> cur = head;;) {
            metrics.add(cur);
            cur = cur.next;
            if (cur == null) {
                break;
            }
        }
        return metrics.iterator();
    }
}

destroy() 方法,销毁:

void destroy(PoolArena<T> arena) {
    // 循环,销毁 ChunkList 管理的所有 Chunk
    PoolChunk<T> chunk = head;
    while (chunk != null) {
        arena.destroyChunk(chunk);
        chunk = chunk.next;
    }
    // 置空
    head = null;
}

PoolChunkListMetric ,继承 Iterable 接口,PoolChunkList Metric 接口:

public interface PoolChunkListMetric extends Iterable<PoolChunkMetric> {

    /**
     * Return the minimum usage of the chunk list before which chunks are promoted to the previous list.
     */
    int minUsage();

    /**
     * Return the maximum usage of the chunk list after which chunks are promoted to the next list.
     */
    int maxUsage();
}

PoolChunkList 对 PoolChunkMetric 接口的实现:

@Override
public int minUsage() {
    return minUsage0(minUsage);
}

@Override
public int maxUsage() {
    return min(maxUsage, 100);
}
发布了46 篇原创文章 · 获赞 6 · 访问量 3847

猜你喜欢

转载自blog.csdn.net/weixin_43257196/article/details/105276137
今日推荐