内存管理-PooledByteBufAllocator-Huge

PooledByteBufAllocator 即池化的 ByteBuf 分配器,整体算法实现都是比较复杂的,因此我们采用各个击破的方式进行介绍。

目标

1. Huge 堆上内存分配 & 释放

2. Huge 直接内存分配 & 释放

3. 了解 ByteBuf 是怎样持有堆上内存不让  JVM 回收的

 

示例

 1 public class ByteBufTest {
 2 
 3     public static void main(String[] args) {
 4         ByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT;
 5         int hugeSize = 17 * 1024 * 1024;
 6         ByteBuf hugeHeapBuf = allocator.heapBuffer(hugeSize);
 7         hugeHeapBuf.release();
 8         ByteBuf hugeDirectBuf = allocator.directBuffer(hugeSize);
 9         hugeDirectBuf.release();
10     }
11 }

 

HeapByteBuf

申请

 1 // PoolArena.java
 2 
 3 PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) {
 4         // 创建一个 PooledByteBuf 的壳
 5         PooledByteBuf<T> buf = newByteBuf(maxCapacity);
 6         // 申请空间
 7         allocate(cache, buf, reqCapacity);
 8         return buf;
 9 }
10 
11 ...
12 
13 private void allocateHuge(PooledByteBuf<T> buf, int reqCapacity) {
14         // huge 的 chunk 是 Unpooled 类型的
15         PoolChunk<T> chunk = newUnpooledChunk(reqCapacity);
16         activeBytesHuge.add(chunk.chunkSize());
17         // 将这一部分空间交给 buf 来持有
18         buf.initUnpooled(chunk, reqCapacity);
19         allocationsHuge.increment();
20 }
21 
22 ...
23 
24 protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
25         // newByteArray 在堆上申请空间,PoolChunk 中持有一个 memory 指向这片空间    
26         return new PoolChunk<byte[]>(this, newByteArray(capacity), capacity, 0);
27 }

 

释放

 1 // PooledByteBuf.java
 2 
 3 protected final void deallocate() {
 4         if (handle >= 0) {
 5             final long handle = this.handle;
 6             this.handle = -1;
 7             // 将 memory 置为 null,去掉 ByteBuf 对这一块内存的使用
 8             memory = null;
 9             tmpNioBuf = null;
10             chunk.arena.free(chunk, handle, maxLength, cache);
11             chunk = null;
12             recycle();
13         }
14 }
15 
16 // PooledArena.java
17 void free(PoolChunk<T> chunk, long handle, int normCapacity, PoolThreadCache cache) {
18         if (chunk.unpooled) {
19             // 更新 chunk 的一些统计信息,归还内存到 chunk,由于是堆上的,因此 destroyChunk 什么都没做,交给 GC 来回收
20             int size = chunk.chunkSize();
21             destroyChunk(chunk);
22             activeBytesHuge.add(-size);
23             deallocationsHuge.increment();
24         } ...

 

DirectByteBuf

与 HeapByteBuf 类似,区别在于申请和释放直接内存的地方

申请

private static ByteBuffer allocateDirect(int capacity) {
            return PlatformDependent.useDirectBufferNoCleaner() ?
                    PlatformDependent.allocateDirectNoCleaner(capacity) : ByteBuffer.allocateDirect(capacity);
        }

 

释放

 1 // PoolArena.java
 2 protected void destroyChunk(PoolChunk<ByteBuffer> chunk) {
 3             if (PlatformDependent.useDirectBufferNoCleaner()) {
 4                 // 将 chunk 指向的内存归还给直接内存
 5                 PlatformDependent.freeDirectNoCleaner(chunk.memory);
 6             } else {
 7                 PlatformDependent.freeDirectBuffer(chunk.memory);
 8             }
 9         }
10 
11 // PlatformDepent.java
12 public static void freeDirectNoCleaner(ByteBuffer buffer) {
13         assert USE_DIRECT_BUFFER_NO_CLEANER;
14 
15         int capacity = buffer.capacity();
16 // 采用 unsafe 的方式归还内存        PlatformDependent0.freeMemory(PlatformDependent0.directBufferAddress(buffer));
17         decrementMemoryCounter(capacity);
18     }

 

 

posted @ 2021-04-13 17:27  imengdong  阅读(463)  评论(0)    收藏  举报