PoolArena ,实现 PoolArenaMetric 接口,Netty 对 Jemalloc Arena 的抽象实现类,PoolArena 有两个子类实现:
- HeapArena ,对 Heap 类型的内存分配。
- 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);
}
}
}