Netty之Jemalloc(四)PoolArena

PoolArena ,实现 PoolArenaMetric 接口,Netty 对 Jemalloc Arena 的抽象实现类,PoolArena 有两个子类实现:

  1. HeapArena ,对 Heap 类型的内存分配。
  2. DirectArena ,对 Direct 类型的内存分配。

构造方法:

/**
 * 是否支持 Unsafe 操作
 */
static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();

/**
 * 内存分类
 */
enum SizeClass {
    Tiny,
    Small,
    Normal

    // 还有一个隐藏的,Huge
}

/**
 * {@link #tinySubpagePools} 数组的大小
 *
 * 默认为 32
 */
static final int numTinySubpagePools = 512 >>> 4;

/**
 * 所属 PooledByteBufAllocator 对象
 */
final PooledByteBufAllocator parent;

/**
 * 满二叉树的高度。默认为 11 。
 */
private final int maxOrder;
/**
 * Page 大小,默认 8KB = 8192B
 */
final int pageSize;
/**
 * 从 1 开始左移到 {@link #pageSize} 的位数。默认 13 ,1 << 13 = 8192 。
 */
final int pageShifts;
/**
 * Chunk 内存块占用大小。默认为 16M = 16 * 1024  。
 */
final int chunkSize;
/**
 * 判断分配请求内存是否为 Tiny/Small ,即分配 Subpage 内存块。
 *
 * Used to determine if the requested capacity is equal to or greater than pageSize.
 */
final int subpageOverflowMask;

/**
 * {@link #smallSubpagePools} 数组的大小
 *
 * 默认为 23
 */
final int numSmallSubpagePools;

/**
 * 对齐基准
 */
final int directMemoryCacheAlignment;
/**
 * {@link #directMemoryCacheAlignment} 掩码
 */
final int directMemoryCacheAlignmentMask;

/**
 * tiny 类型的 PoolSubpage 数组
 *
 * 数组的每个元素,都是双向链表
 */
private final PoolSubpage<T>[] tinySubpagePools;
/**
 * small 类型的 SubpagePools 数组
 *
 * 数组的每个元素,都是双向链表
 */
private final PoolSubpage<T>[] smallSubpagePools;

// PoolChunkList 之间的双向链表

private final PoolChunkList<T> q050;
private final PoolChunkList<T> q025;
private final PoolChunkList<T> q000;
private final PoolChunkList<T> qInit;
private final PoolChunkList<T> q075;
private final PoolChunkList<T> q100;

/**
 * PoolChunkListMetric 数组
 */
private final List<PoolChunkListMetric> chunkListMetrics;

// Metrics for allocations and deallocations
/**
 * 分配 Normal 内存块的次数
 */
private long allocationsNormal;
// We need to use the LongCounter here as this is not guarded via synchronized block.
/**
 * 分配 Tiny 内存块的次数
 */
private final LongCounter allocationsTiny = PlatformDependent.newLongCounter();
/**
 * 分配 Small 内存块的次数
 */
private final LongCounter allocationsSmall = PlatformDependent.newLongCounter();
/**
 * 分配 Huge 内存块的次数
 */
private final LongCounter allocationsHuge = PlatformDependent.newLongCounter();
/**
 * 正在使用中的 Huge 内存块的总共占用字节数
 */
private final LongCounter activeBytesHuge = PlatformDependent.newLongCounter();

/**
 * 释放 Tiny 内存块的次数
 */
private long deallocationsTiny;
/**
 * 释放 Small 内存块的次数
 */
private long deallocationsSmall;
/**
 * 释放 Normal 内存块的次数
 */
private long deallocationsNormal;

/**
 * 释放 Huge 内存块的次数
 */
// We need to use the LongCounter here as this is not guarded via synchronized block.
private final LongCounter deallocationsHuge = PlatformDependent.newLongCounter();

/**
 * 该 PoolArena 被多少线程引用的计数器
 */
// Number of thread caches backed by this arena.
final AtomicInteger numThreadCaches = new AtomicInteger();

  protected PoolArena(PooledByteBufAllocator parent, int pageSize,
        int maxOrder, int pageShifts, int chunkSize, int cacheAlignment) {
      this.parent = parent;
      this.pageSize = pageSize;
      this.maxOrder = maxOrder;
      this.pageShifts = pageShifts;
      this.chunkSize = chunkSize;
      directMemoryCacheAlignment = cacheAlignment;
      directMemoryCacheAlignmentMask = cacheAlignment - 1;
      subpageOverflowMask = ~(pageSize - 1);
  
      // 初始化 tinySubpagePools 数组
      tinySubpagePools = newSubpagePoolArray(numTinySubpagePools);
      for (int i = 0; i < tinySubpagePools.length; i ++) {
          tinySubpagePools[i] = newSubpagePoolHead(pageSize);
      }
  
      // 初始化 smallSubpagePools 数组
      numSmallSubpagePools = pageShifts - 9;
      smallSubpagePools = newSubpagePoolArray(numSmallSubpagePools);
      for (int i = 0; i < smallSubpagePools.length; i ++) {
          smallSubpagePools[i] = newSubpagePoolHead(pageSize);
      }
  
      // PoolChunkList 之间的双向链表,初始化
  
      q100 = new PoolChunkList<T>(this, null, 100, Integer.MAX_VALUE, chunkSize);
      q075 = new PoolChunkList<T>(this, q100, 75, 100, chunkSize);
      q050 = new PoolChunkList<T>(this, q075, 50, 100, chunkSize);
      q025 = new PoolChunkList<T>(this, q050, 25, 75, chunkSize);
      q000 = new PoolChunkList<T>(this, q025, 1, 50, chunkSize);
      qInit = new PoolChunkList<T>(this, q000, Integer.MIN_VALUE, 25, chunkSize);
  
      q100.prevList(q075);
      q075.prevList(q050);
      q050.prevList(q025);
      q025.prevList(q000);
      q000.prevList(null); // 无前置节点
      qInit.prevList(qInit); // 前置节点为自己
  
      // 创建 PoolChunkListMetric 数组
      List<PoolChunkListMetric> metrics = new ArrayList<PoolChunkListMetric>(6);
      metrics.add(qInit);
      metrics.add(q000);
      metrics.add(q025);
      metrics.add(q050);
      metrics.add(q075);
      metrics.add(q100);
      chunkListMetrics = Collections.unmodifiableList(metrics);
  }

normalizeCapacity(int reqCapacity) 方法,标准化请求分配的内存大小。通过这样的方式,保证分配的内存块统一:

 int normalizeCapacity(int reqCapacity) {
     if (reqCapacity < 0) {
         throw new IllegalArgumentException("capacity: " + reqCapacity + " xpected: 0+)");
     }
 
     // Huge 内存类型,直接使用 reqCapacity ,无需进行标准化。
     if (reqCapacity >= chunkSize) {
         return directMemoryCacheAlignment == 0 ? reqCapacity : alignCapacity(reqCapacity);
     }
 
     // 非 tiny 内存类型
     if (!isTiny(reqCapacity)) { // >= 512
        // Doubled
         // 转换成接近于两倍的容量
         int normalizedCapacity = reqCapacity;
         normalizedCapacity --;
         normalizedCapacity |= normalizedCapacity >>>  1;
         normalizedCapacity |= normalizedCapacity >>>  2;
         normalizedCapacity |= normalizedCapacity >>>  4;
         normalizedCapacity |= normalizedCapacity >>>  8;
         normalizedCapacity |= normalizedCapacity >>> 16;
         normalizedCapacity ++;
         if (normalizedCapacity < 0) {
             normalizedCapacity >>>= 1;
         }
         assert directMemoryCacheAlignment == 0 || (normalizedCapacity & directMemoryCacheAlignmentMask) == 0;
 
         return normalizedCapacity;
     }
 
     if (directMemoryCacheAlignment > 0) {
         return alignCapacity(reqCapacity);
     }
 
     // 补齐成 16 的倍数
     // Quantum-spaced
     if ((reqCapacity & 15) == 0) {
        return reqCapacity;
     }
     return (reqCapacity & ~15) + 16;
 }

嗷嗷嗷Subpage篇说过Tiny,Small,这篇补充下Normal和Huge,当大小在8KB - 16MB间,不属于Subpage,属于一个Chunk中的一个Page,即就是Normal内存块;当 > 16MB,属于Huge内存块,即就是一整个Chunk内存块。

alignCapacity(int reqCapacity) 方法,对齐请求分配的内存大小:

int alignCapacity(int reqCapacity) {
    // 获得 delta
    int delta = reqCapacity & directMemoryCacheAlignmentMask;
    // 补齐 directMemoryCacheAlignment ,并减去 delta
    return delta == 0 ? reqCapacity : reqCapacity + directMemoryCacheAlignment - delta;
}

isTinyOrSmall(int normCapacity) 方法,判断请求分配的内存类型是否为 tiny 或 small 类型:

// capacity < pageSize
boolean isTinyOrSmall(int normCapacity) {
    return (normCapacity & subpageOverflowMask) == 0;
}

isTiny(int normCapacity) 方法,判断请求分配的内存类型是否为 tiny 类型:

// normCapacity < 512
static boolean isTiny(int normCapacity) {
    return (normCapacity & 0xFFFFFE00) == 0;
}

tinyIdx(int normCapacity) 静态方法,计算请求分配的内存大小在 tinySubpagePools 数组的下标:

static int tinyIdx(int normCapacity) {
    return normCapacity >>> 4;
}

smallIdx(int normCapacity) 静态方法,计算请求分配的内存大小在 smallSubpagePools 数组的下标:

static int smallIdx(int normCapacity) {
    int tableIdx = 0;
    int i = normCapacity >>> 10;
    while (i != 0) {
        i >>>= 1;
        tableIdx ++;
    }
    return tableIdx;
}

sizeClass(int normCapacity) 方法,计算请求分配的内存的内存类型:

private SizeClass sizeClass(int normCapacity) {
    if (!isTinyOrSmall(normCapacity)) {
        return SizeClass.Normal;
    }
    return isTiny(normCapacity) ? SizeClass.Tiny : SizeClass.Small;
}

findSubpagePoolHead(int elemSize) 方法,获得请求分配的 Subpage 类型的内存的链表的头节点:

PoolSubpage<T> findSubpagePoolHead(int elemSize) {
    int tableIdx;
    PoolSubpage<T>[] table;
    if (isTiny(elemSize)) { // < 512
        // 实际上,就是 `#tinyIdx(int normCapacity)` 方法
        tableIdx = elemSize >>> 4;
        // 获得 table
        table = tinySubpagePools;
    } else {
        // 实际上,就是 `#smallIdx(int normCapacity)` 方法
        tableIdx = 0;
        elemSize >>>= 10;
        while (elemSize != 0) {
            elemSize >>>= 1;
            tableIdx ++;
        }
        // 获得 table
        table = smallSubpagePools;
    }

    // 获得 Subpage 链表的头节点
    return table[tableIdx];
}

allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) 方法,创建 PooledByteBuf 对象,并分配内存块给 PooledByteBuf 对象:

 private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {
     // 标准化请求分配的容量
     final int normCapacity = normalizeCapacity(reqCapacity);
     // PoolSubpage 的情况
     if (isTinyOrSmall(normCapacity)) { // capacity < pageSize
         int tableIdx;
         PoolSubpage<T>[] table;
         // 判断是否为 tiny 类型的内存块申请
         boolean tiny = isTiny(normCapacity);
         if (tiny) { // < 512 tiny 类型的内存块申请
             // 从 PoolThreadCache 缓存中,分配 tiny 内存块,并初始化到 PooledByteBuf 中。
             if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {
                 // was able to allocate out of the cache so move on
                 return;
             }
             // 获得 tableIdx 和 table 属性
             tableIdx = tinyIdx(normCapacity);
             table = tinySubpagePools;
         } else {
             // 从 PoolThreadCache 缓存中,分配 small 内存块,并初始化到 PooledByteBuf 中。
             if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {
                 // was able to allocate out of the cache so move on
                 return;
             }
             // 获得 tableIdx 和 table 属性
             tableIdx = smallIdx(normCapacity);
             table = smallSubpagePools;
         }
 
         // 获得 PoolSubpage 链表的头节点
         final PoolSubpage<T> head = table[tableIdx];
 
         // 从 PoolSubpage 链表中,分配 Subpage 内存块
         /**
          * Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and
          * {@link PoolChunk#free(long)} may modify the doubly linked list as well.
          */
         synchronized (head) { // 同步 head ,避免并发问题
             final PoolSubpage<T> s = head.next;
            if (s != head) {
                 assert s.doNotDestroy && s.elemSize == normCapacity;
                 // 分配 Subpage 内存块
                 long handle = s.allocate();
                 assert handle >= 0;
                 // 初始化 Subpage 内存块到 PooledByteBuf 对象中
                 s.chunk.initBufWithSubpage(buf, handle, reqCapacity);
                 // 增加 allocationsTiny 或 allocationsSmall 计数
                 incTinySmallAllocation(tiny);
                 // 返回,因为已经分配成功
                 return;
             }
         }
         // 申请 Normal Page 内存块。实际上,只占用其中一块 Subpage 内存块。
         synchronized (this) { // 同步 arena ,避免并发问题
             allocateNormal(buf, reqCapacity, normCapacity);
         }
         // 增加 allocationsTiny 或 allocationsSmall 计数
         incTinySmallAllocation(tiny);
         // 返回,因为已经分配成功
         return;
     }
     if (normCapacity <= chunkSize) {
         // 从 PoolThreadCache 缓存中,分配 normal 内存块,并初始化到 PooledByteBuf 中。
        if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {
            // was able to allocate out of the cache so move on
             return;
         }
         // 申请 Normal Page 内存块
         synchronized (this) { // 同步 arena ,避免并发问题
             allocateNormal(buf, reqCapacity, normCapacity);
             // 增加 allocationsNormal
             ++allocationsNormal;
         }
     } else {
         // 申请 Huge Page 内存块
         // Huge allocations are never served via the cache so just call allocateHuge
         allocateHuge(buf, reqCapacity);
     }
 }

allocateNormal(PooledByteBuf buf, int reqCapacity, int normCapacity) 方法,申请 Normal Page 内存块:

   // Method must be called inside synchronized(this) { ... } block // 必须在 synchronized(this) { ... } 中执行
 private void allocateNormal(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
     // 按照优先级,从多个 ChunkList 中,分配 Normal Page 内存块。如果有一分配成功,返回
     if (q050.allocate(buf, reqCapacity, normCapacity) || q025.allocate(buf, reqCapacity, normCapacity) ||
         q000.allocate(buf, reqCapacity, normCapacity) || qInit.allocate(buf, reqCapacity, normCapacity) ||
         q075.allocate(buf, reqCapacity, normCapacity)) {
         return;
     }
 
     // Add a new chunk.
     // 新建 Chunk 内存块
     PoolChunk<T> c = newChunk(pageSize, maxOrder, pageShifts, chunkSize);
     // 申请对应的 Normal Page 内存块。实际上,如果申请分配的内存类型为 tiny 或 small 类型,实际申请的是 Subpage 内存块。
     long handle = c.allocate(normCapacity);
     assert handle > 0;
     // 初始化 Normal Page / Subpage 内存块到 PooledByteBuf 对象中
     c.initBuf(buf, handle, reqCapacity);
     // 添加到 ChunkList 双向链中。
     qInit.add(c);
 }
 /*那么为什么选择从 q050 开始?

1、q050 保存的是内存利用率 50%~100% 的 chunk ,这应该是个折中的选择!这样大部分情况下,chunk 的利用率都会保持在一个较高水平,提高整个应用的内存利用率;
2、qinit 的 chunk 利用率低,但不会被回收;
3、q075 和 q100 由于内存利用率太高,导致内存分配的成功率大大降低,因此放到最后;*/

allocateHuge(PooledByteBuf buf, int reqCapacity) 方法,申请 Huge 内存块:

 private void allocateHuge(PooledByteBuf<T> buf, int reqCapacity) {
     // 新建 Chunk 内存块,它是 unpooled 的
     PoolChunk<T> chunk = newUnpooledChunk(reqCapacity);
     // 增加 activeBytesHuge
     activeBytesHuge.add(chunk.chunkSize());
     // 初始化 Huge 内存块到 PooledByteBuf 对象中
     buf.initUnpooled(chunk, reqCapacity);
     // 增加 allocationsHuge
     allocationsHuge.increment();
 }

newUnpooledChunk(int capacity) 抽象方法,新建 unpooled Chunk 内存块。需要 PoolArea 子类实现该方法:

protected abstract PoolChunk<T> newUnpooledChunk(int capacity); 

reallocate(PooledByteBuf buf, int newCapacity, boolean freeOldMemor) 方法,因为要扩容或缩容,所以重新分配合适的内存块给 PooledByteBuf 对象:

 void reallocate(PooledByteBuf<T> buf, int newCapacity, boolean freeOldMemory) {
     if (newCapacity < 0 || newCapacity > buf.maxCapacity()) {
         throw new IllegalArgumentException("newCapacity: " + newCapacity);
     }
 
     // 容量大小没有变化,直接返回
     int oldCapacity = buf.length;
     if (oldCapacity == newCapacity) {
         return;
     }
 
     // 记录老的内存块的信息
     PoolChunk<T> oldChunk = buf.chunk;
     long oldHandle = buf.handle;
     T oldMemory = buf.memory;
     int oldOffset = buf.offset;
     int oldMaxLength = buf.maxLength;
 
     // 记录读写索引
     int readerIndex = buf.readerIndex();
     int writerIndex = buf.writerIndex();
 
     // 分配新的内存块给 PooledByteBuf 对象
     allocate(parent.threadCache(), buf, newCapacity);
 
     // 扩容
     if (newCapacity > oldCapacity) {
         // 将老的内存块的数据,复制到新的内存块中
         memoryCopy(
                 oldMemory, oldOffset,
                 buf.memory, buf.offset, oldCapacity);
     // 缩容
     } else {
         // 有部分数据未读取完
         if (readerIndex < newCapacity) {
             // 如果 writerIndex 大于 newCapacity ,重置为 newCapacity ,避免越界
             if (writerIndex > newCapacity) {
                 writerIndex = newCapacity;
             }
             // 将老的内存块的数据,复制到新的内存块中
             memoryCopy(
                    oldMemory, oldOffset + readerIndex,
                     buf.memory, buf.offset + readerIndex, writerIndex - readerIndex);
         // 全部读完,重置 readerIndex 和 writerIndex 为 newCapacity ,避免越界
         } else {
             readerIndex = writerIndex = newCapacity;
         }
     }
 
     // 设置读写索引
     buf.setIndex(readerIndex, writerIndex);
 
     // 释放老的内存块
     if (freeOldMemory) {
         free(oldChunk, oldHandle, oldMaxLength, buf.cache);
     }
 }

free(PoolChunk chunk, long handle, int normCapacity, PoolThreadCache cache) 方法,释放内存块:

 void free(PoolChunk<T> chunk, long handle, int normCapacity, PoolThreadCache cache) {
     if (chunk.unpooled) {
         int size = chunk.chunkSize();
         // 直接销毁 Chunk 内存块,因为占用空间较大
         destroyChunk(chunk);
         // 减少 activeBytesHuge 计数
         activeBytesHuge.add(-size);
        // 减少 deallocationsHuge 计数
         deallocationsHuge.increment();
     } else {
         // 计算内存的 SizeClass
         SizeClass sizeClass = sizeClass(normCapacity);
         // 添加内存块到 PoolThreadCache 缓存
         if (cache != null && cache.add(this, chunk, handle, normCapacity, sizeClass)) {
             // cached so not free it.
             return;
        }
         // 释放 Page / Subpage 内存块回 Chunk 中
         freeChunk(chunk, handle, sizeClass);
     }
 }

freeChunk(PoolChunk chunk, long handle, SizeClass sizeClass) 方法,释放指定位置的 Page / Subpage 内存块回 Chunk 中:

 void freeChunk(PoolChunk<T> chunk, long handle, SizeClass sizeClass) {
     final boolean destroyChunk;
     synchronized (this) { // 锁,避免并发
         // 减小相应的计数
         switch (sizeClass) {
         case Normal:
             ++deallocationsNormal;
             break;
         case Small:
             ++deallocationsSmall;
             break;
         case Tiny:
             ++deallocationsTiny;
             break;
         default:
             throw new Error();
         }
         // 释放指定位置的内存块
         destroyChunk = !chunk.parent.free(chunk, handle);
     }
     // 当 destroyChunk 为 true 时,意味着 Chunk 中不存在在使用的 Page / Subpage 内存块。也就是说,内存使用率为 0 ,所以销毁 Chunk
     if (destroyChunk) {
         // destroyChunk not need to be called while holding the synchronized lock.
         destroyChunk(chunk);
     }
 }

在 PoolArena 对象被 GC 回收时,清理其管理的内存。( 主要是为了清理对外内存 ):

@Override
protected final void finalize() throws Throwable {
    try {
        // 调用父方法
        super.finalize();
    } finally {
        // 清理 tiny Subpage 们
        destroyPoolSubPages(smallSubpagePools);
        // 清理 small Subpage 们
        destroyPoolSubPages(tinySubpagePools);
        // 清理 ChunkList 们
        destroyPoolChunkLists(qInit, q000, q025, q050, q075, q100);
    }
}

private static void destroyPoolSubPages(PoolSubpage<?>[] pages) {
    for (PoolSubpage<?> page : pages) {
        page.destroy();
    }
}

private void destroyPoolChunkLists(PoolChunkList<T>... chunkLists) {
    for (PoolChunkList<T> chunkList: chunkLists) {
        chunkList.destroy(this);
    }
}

几个抽象方法:

abstract boolean isDirect();

protected abstract PoolChunk<T> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize); //
protected abstract PoolChunk<T> newUnpooledChunk(int capacity); //

protected abstract PooledByteBuf<T> newByteBuf(int maxCapacity);

protected abstract void memoryCopy(T src, int srcOffset, T dst, int dstOffset, int length); //
    
protected abstract void destroyChunk(PoolChunk<T> chunk);

HeapArena ,继承 PoolArena 抽象类,对 Heap 类型的内存分配,简单内部静态类:

static final class HeapArena extends PoolArena<byte[]> { // 管理 byte[] 数组

    HeapArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
        super(parent, pageSize, maxOrder, pageShifts, chunkSize, directMemoryCacheAlignment);
    }

    private static byte[] newByteArray(int size) {
        return PlatformDependent.allocateUninitializedArray(size); // 创建 byte[] 数组
    }

    @Override
    boolean isDirect() {
        return false;
    }

    @Override
    protected PoolChunk<byte[]> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) {
        return new PoolChunk<byte[]>(this, newByteArray(chunkSize), pageSize, maxOrder, pageShifts, chunkSize, 0);
    }

    @Override
    protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
        return new PoolChunk<byte[]>(this, newByteArray(capacity), capacity, 0);
    }

    @Override
    protected void destroyChunk(PoolChunk<byte[]> chunk) {
        // Rely on GC. 依赖 GC
    }

    @Override
    protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) {
        return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity)
                : PooledHeapByteBuf.newInstance(maxCapacity);
    }

    @Override
    protected void memoryCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) {
        if (length == 0) {
            return;
        }

        System.arraycopy(src, srcOffset, dst, dstOffset, length);
    }
}

DirectArena ,继承 PoolArena 抽象类,对 Direct 类型的内存分配:

static final class DirectArena extends PoolArena<ByteBuffer> { // 管理 Direct ByteBuffer 对象

    DirectArena(PooledByteBufAllocator parent, int pageSize, int maxOrder,
            int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
        super(parent, pageSize, maxOrder, pageShifts, chunkSize, directMemoryCacheAlignment);
    }

    @Override
    boolean isDirect() {
        return true;
    }

    private int offsetCacheLine(ByteBuffer memory) {
        // We can only calculate the offset if Unsafe is present as otherwise directBufferAddress(...) will
        // throw an NPE.
        return HAS_UNSAFE ?
                (int) (PlatformDependent.directBufferAddress(memory) & directMemoryCacheAlignmentMask) : 0;
    }

    @Override
    protected PoolChunk<ByteBuffer> newChunk(int pageSize, int maxOrder,
            int pageShifts, int chunkSize) {
        if (directMemoryCacheAlignment == 0) {
            return new PoolChunk<ByteBuffer>(this, allocateDirect(chunkSize), pageSize, maxOrder, pageShifts, chunkSize, 0);
        }
        final ByteBuffer memory = allocateDirect(chunkSize + directMemoryCacheAlignment);
        return new PoolChunk<ByteBuffer>(this, memory, pageSize, maxOrder, pageShifts, chunkSize, offsetCacheLine(memory));
    }

    @Override
    protected PoolChunk<ByteBuffer> newUnpooledChunk(int capacity) {
        if (directMemoryCacheAlignment == 0) {
            return new PoolChunk<ByteBuffer>(this,
                    allocateDirect(capacity), capacity, 0);
        }
        final ByteBuffer memory = allocateDirect(capacity + directMemoryCacheAlignment);
        return new PoolChunk<ByteBuffer>(this, memory, capacity, offsetCacheLine(memory));
    }

    private static ByteBuffer allocateDirect(int capacity) { // 创建 Direct ByteBuffer 对象
        return PlatformDependent.useDirectBufferNoCleaner() ?
                PlatformDependent.allocateDirectNoCleaner(capacity) : ByteBuffer.allocateDirect(capacity);
    }

    @Override
    protected void destroyChunk(PoolChunk<ByteBuffer> chunk) {
        if (PlatformDependent.useDirectBufferNoCleaner()) {
            PlatformDependent.freeDirectNoCleaner(chunk.memory);
        } else {
            PlatformDependent.freeDirectBuffer(chunk.memory);
        }
    }

    @Override
    protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) {
        if (HAS_UNSAFE) {
            return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);
        } else {
            return PooledDirectByteBuf.newInstance(maxCapacity);
        }
    }

    @Override
    protected void memoryCopy(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int length) {
        if (length == 0) {
            return;
        }

        if (HAS_UNSAFE) {
            PlatformDependent.copyMemory(
                    PlatformDependent.directBufferAddress(src) + srcOffset,
                    PlatformDependent.directBufferAddress(dst) + dstOffset, length);
        } else {
            // We must duplicate the NIO buffers because they may be accessed by other Netty buffers.
            src = src.duplicate();
            dst = dst.duplicate();
            src.position(srcOffset).limit(srcOffset + length);
            dst.position(dstOffset);
            dst.put(src);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值