UnpooledHeapByteBuf
是 Netty 中基于堆内存(JVM 堆)的非池化字节缓冲区实现。它直接使用 Java 的 byte[]
数组作为底层存储,适用于常规的 JVM 堆内存分配场景。核心特点如下:
AbstractReferenceCountedByteBuf
,通过引用计数管理生命周期。protected byte[] array; // 底层字节数组
// 构造方法:分配新数组
public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
setArray(allocateArray(initialCapacity)); // 内部调用 new byte[initialCapacity]
}
// 构造方法:复用现有数组
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
setArray(initialArray);
}
allocateArray()
创建新数组(可被子类覆盖,如 UnpooledUnsafeHeapByteBuf
使用 PlatformDependent.allocateUninitializedArray()
避免清零)。setArray()
更新数组引用并重置 tmpNioBuf
(用于 NIO 转换的临时缓冲区)。capacity(int newCapacity)
)public ByteBuf capacity(int newCapacity) {
// 1. 检查新容量合法性
checkNewCapacity(newCapacity);
// 2. 计算需复制的数据量
int bytesToCopy = Math.min(oldCapacity, newCapacity);
// 3. 创建新数组并复制数据
byte[] newArray = allocateArray(newCapacity);
System.arraycopy(oldArray, 0, newArray, 0, bytesToCopy);
// 4. 更新数组并释放旧资源
setArray(newArray);
freeArray(oldArray); // 默认空操作(由GC回收)
}
System.arraycopy
避免逐字节操作。trimIndicesToCapacity()
确保读写索引不越界。freeArray()
可被子类覆盖(如池化场景)。_getByte()
/ _setByte()
)// 直接通过数组下标访问
protected byte _getByte(int index) {
return HeapByteBufUtil.getByte(array, index);
}
protected void _setByte(int index, int value) {
HeapByteBufUtil.setByte(array, index, value);
}
_xxx
)跳过重复检查,由公共方法(如 getByte()
)提前调用 ensureAccessible()
和索引验证。HeapByteBufUtil
封装字节序转换逻辑(如 getShortLE()
处理小端序)。NIO 缓冲区转换
private ByteBuffer internalNioBuffer() {
if (tmpNioBuf == null) {
tmpNioBuf = ByteBuffer.wrap(array); // 复用数组,零拷贝
}
return tmpNioBuf;
}
public ByteBuffer nioBuffer(int index, int length) {
return ByteBuffer.wrap(array, index, length).slice();
}
ByteBuffer.wrap()
共享底层数组,避免数据复制。internalNioBuffer()
缓存实例减少对象分配。deallocate()
)protected void deallocate() {
freeArray(array); // 默认空操作
array = EmptyArrays.EMPTY_BYTES; // 指向空数组,加速GC
}
freeArray()
为扩展点(如 InstrumentedUnpooledHeapByteBuf
在此更新内存统计)。UnpooledUnsafeHeapByteBuf
的对比子类 UnpooledUnsafeHeapByteBuf
通过 Unsafe API 进一步优化:
// 使用未初始化数组(避免清零开销)
protected byte[] allocateArray(int initialCapacity) {
return PlatformDependent.allocateUninitializedArray(initialCapacity);
}
// 直接通过 Unsafe 操作数组
protected byte _getByte(int index) {
return UnsafeByteBufUtil.getByte(array, index);
}
难点:索引与边界控制
trimIndicesToCapacity()
在缩容时调整索引,防止越界。getBytes()
)调用 checkDstIndex()
和 ensureAccessible()
确保安全。学习点:设计模式应用
模板方法模式:
AbstractReferenceCountedByteBuf
定义引用计数骨架,子类实现 deallocate()
。allocateArray()
/freeArray()
为扩展点(如支持非清零分配)。零拷贝优化:
nioBuffer()
共享底层数组,减少数据传输开销。内存分层设计:
UnpooledDirectByteBuf
使用 ByteBuffer.allocateDirect()
,通过 memoryAddress()
支持直接内存操作。UnpooledHeapByteBuf
的核心价值在于:
byte[]
的实现易于理解,适合堆内存场景。适用场景:高频创建/销毁的临时缓冲区、非 I/O 密集业务逻辑处理。对于需要直接内存操作的网络 I/O,可切换到 UnpooledDirectByteBuf
。
UnpooledUnsafeHeapByteBuf
vs UnpooledHeapByteBuf
1. 底层数组初始化策略(关键性能差异)
// UnpooledHeapByteBuf
protected byte[] allocateArray(int initialCapacity) {
return new byte[initialCapacity]; // JVM 强制清零初始化
}
// UnpooledUnsafeHeapByteBuf
protected byte[] allocateArray(int initialCapacity) {
return PlatformDependent.allocateUninitializedArray(initialCapacity); // 免清零分配
}
new byte[N]
触发 JVM 对内存块的强制清零(安全但昂贵)setByte/setBytes
控制写入保证安全内存访问机制(CPU指令级优化)
// UnpooledHeapByteBuf (标准数组访问)
protected short _getShort(int index) {
return HeapByteBufUtil.getShort(array, index); // 数组边界检查
}
// UnpooledUnsafeHeapByteBuf (Unsafe直接操作)
protected short _getShort(int index) {
return UnsafeByteBufUtil.getShort(array, index); // 底层sun.misc.Unsafe
}
getShort(Object, offset)
等单条CPU指令操作内存checkIndex
)3. 批量清零操作(setZero
优化)
// UnpooledHeapByteBuf (文档1)
// 无直接实现 => 默认循环setByte(0)
public ByteBuf setZero(int index, int length) {
for (int i = index, end = index + length; i < end; i++) {
_setByte(i, 0);
}
}
// UnpooledUnsafeHeapByteBuf (文档7)
public ByteBuf setZero(int index, int length) {
UnsafeByteBufUtil.setZero(array, index, length); // 批量清零
}
Unsafe.setMemory
单次调用填充大块内存Arrays.fill
的 JVM 内联优化)非对齐访问优化
// UnpooledUnsafeHeapByteBuf
@Override @Deprecated
protected SwappedByteBuf newSwappedByteBuf() {
if (PlatformDependent.isUnaligned()) {
return new UnsafeHeapSwappedByteBuf(this); // 非对齐优化
}
return super.newSwappedByteBuf();
}
UnsafeHeapSwappedByteBuf
PlatformDependent.isUnaligned()
动态检测)与分配器的协同优化
// UnpooledByteBufAllocator
protected ByteBuf newHeapBuffer(int cap, int max) {
return PlatformDependent.hasUnsafe() ?
new InstrumentedUnpooledUnsafeHeapByteBuf(this, cap, max) :
new InstrumentedUnpooledHeapByteBuf(this, cap, max);
}
PlatformDependent.hasUnsafe()
启用优化Instrumented
包装实现// 内存统计示例
void incrementHeap(int amount) {
metric.heapCounter.add(amount); // 实时监控堆内存
}
UnpooledUnsafeHeapByteBuf
通过三大核心优化:
适用场景:
代价:
Netty 通过 PlatformDependent
检测和回退机制,在保证兼容性的前提下最大化性能,展现了高性能框架的优化哲学。
核心功能:
直接内存分配器,绕过 JVM 的 Cleaner 机制,通过 Netty 自建引用计数管理直接内存生命周期。
结构亮点:
@Override
protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
return PlatformDependent.allocateDirectBufferNoCleaner(capacity); // 无Cleaner分配
}
CleanableDirectBuffer reallocateDirect(CleanableDirectBuffer oldBuffer, int newCapacity) {
return PlatformDependent.reallocateDirectBufferNoCleaner(oldBuffer, newCapacity); // 内存扩容
}
深入分析:
ByteBuffer.allocateDirect()
的 Cleaner
开销(减少 GC 压力)reallocateDirect()
实现原地扩容(对比 JDK 直接内存必须重新分配)
直接内存的精细控制策略,适用于高频扩容场景(如动态协议解析)
核心功能:
创建零拷贝的 ByteBuf 镜像视图,共享底层存储但独立维护读写索引。
结构设计:
// 所有读写操作委托给原缓冲区
protected short _getShort(int index) {
return unwrap()._getShort(index); // 直接调用原缓冲方法
}
protected void _setShort(int index, int value) {
unwrap()._setShort(index, value); // 修改直接作用到原数据
}
深入分析:
readerIndex
/writerIndex
隔离)应用场景:
协议解码时分拆多消息(如 HTTP2 的 HEADERS + DATA 帧共享底层 TCP 数据)
核心功能:
创建数据分片的零拷贝视图,类似 ByteBuffer.slice()
但支持动态扩展。
核心算法:
// 索引转换:虚拟索引→物理索引
private int idx(int index) {
return index + adjustment; // adjustment = 分片起始偏移量
}
protected byte _getByte(int index) {
return unwrap()._getByte(idx(index)); // 物理索引访问
}
深入分析:
capacity()
固定为切片长度(禁止越界)maxCapacity()
仍为原缓冲区上限(支持扩展)// 当切片写入需扩容时
public ByteBuf writeByte(int value) {
ensureWritable(1); // 触发原缓冲区扩容
super.writeByte(value);
}
对比 Duplicated:
特性 | Duplicated | Sliced |
---|---|---|
数据范围 | 整个缓冲区 | 子区间 |
索引起点 | 0 | 自定义偏移量 |
容量扩展 | 否 | 通过原缓冲区支持 |
核心功能:
基于 Unsafe API 的直接内存操作器,最大化直接内存访问性能。
关键实现:
// 内存地址计算
final long addr(int index) {
return memoryAddress + index; // 直接内存绝对地址
}
protected long _getLong(int index) {
return UnsafeByteBufUtil.getLong(addr(index)); // Unsafe内存访问
}
特殊机制:
protected SwappedByteBuf newSwappedByteBuf() {
if (PlatformDependent.isUnaligned()) {
return new UnsafeDirectSwappedByteBuf(this); // 非对齐加速
}
return super.newSwappedByteBuf();
}
public ByteBuf writeZero(int length) {
UnsafeByteBufUtil.setZero(addr(writerIndex), length);
}
核心功能:
标准 JNI 直接内存实现,提供跨平台安全访问。
UnpooledDirectByteBuf
的直接内存分配是一个委托模式的实现:
PlatformDependent
进行实际的直接内存分配CleanableDirectBuffer
封装了内存清理逻辑deallocate()
确保内存正确释放CleanableDirectBuffer
是由 PlatformDependent.allocateDirect()
创建并返回
分层防御设计:
内存访问保护:
public byte getByte(int index) {
ensureAccessible(); // 引用计数检查
return buffer.get(index); // 标准ByteBuffer操作
}
越界双校验:
checkIndex(index, length)
Buffer.position(index).limit(index+length)
安全释放:
protected void deallocate() {
if (cleanable != null) {
cleanable.clean(); // 通过Cleaner释放
} else {
freeDirect(buffer); // 降级为JNI释放
}
}
四大核心实现:
Duplicated/Sliced
避免数据复制LongAdder
计数 + 泄漏追踪选型建议:
场景 | 推荐实现 |
---|---|
短生命周期小对象 | UnpooledHeapByteBuf |
高频临时缓冲区 | UnpooledUnsafeHeapByteBuf |
长生命周期直接内存 | UnpooledUnsafeNoCleanerDirectByteBuf |
协议解析中间件 | UnpooledSlicedByteBuf |
内存敏感型系统 | Instrumented 包装类 + 分配监控 |