Netty源码分析(一) ByteBuf
ByteBuf是netty的核心,一般我们使用java.nio.ByteBuffer时,由于其只有一个指针(offset),读写时必须使用flip()归位指针等操作,ByteBuf作为netty的核心类,使用readerIndex,writerIndex2个指针分离读写偏移控制,增加markedReaderIndex/markedWriterIndex 标记读写位置用于复制/重置等扩展操作。
+-------------------+------------------+------------------+
| discardable bytes | readable bytes | writable bytes |
+-------------------+------------------+------------------+
| | | |
0 <= readerIndex <= writerIndex <= capacity
整个ByteBuf的类关系图如下(基于Netty-4.1.6):
ByteBuf.jpgByteBuf可以分为3类,WrappedByteBuf用于包装,AbstractDerivedByteBuf/AbstractPooledDerivedByteBuf用于衍生扩展
AbstractByteBuf用于实现具体操作,
A区域内就是经常会使用到的具体实现,这一节我们具体看下这些类。
AbstractByteBuf
包含了索引计算/标记等工作,并将具体内存实现委派到子类。
AbstractReferenceCountedByteBuf
从AbstractByteBuf继承下来的AbstractReferenceCountedByteBuf增加了计数器功能,通过retain()函数增加计数,release()函数减少计数,当计数器减为0时触发deallocate()释放缓冲区内存
private boolean release0(int decrement) {
for (;;) {
int refCnt = this.refCnt;
if (refCnt < decrement) {
throw new IllegalReferenceCountException(refCnt, -decrement);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) {
if (refCnt == decrement) {
deallocate();
return true;
}
return false;
}
}
}
/**
* Called once {@link #refCnt()} is equals 0.
*/
protected abstract void deallocate();
UnpooledUnsafeDirectByteBuf
使用堆外内存作为缓冲区,通过Unsafe类处理内存读写。
UnpooledUnsafeNoCleanerDirectByteBuf
和UnpooledUnsafeDirectByteBuf最大区别在于UnpooledUnsafeNoCleanerDirectByteBuf在allocate的时候通过反射构造函数的方式创建DirectByteBuffer,这样在DirectByteBuffer中没有对应的Cleaner函数(通过ByteBuffer.allocateDirect的方式会自动生成Cleaner函数,Cleaner用于内存回收,具体可以看源码),内存回收时,UnpooledUnsafeDirectByteBuf通过调用DirectByteBuffer中的Cleaner函数回收,而UnpooledUnsafeNoCleanerDirectByteBuf直接使用UNSAFE.freeMemory(address)释放内存地址。
WrappedUnpooledUnsafeDirectByteBuf
创建一个指定内存地址的UnpooledUnsafeDirectByteBuf,该内存块可能已被写入数据以减少一步拷贝操作。
UnpooledHeapByteBuf
使用java heap作为缓冲区
private UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity)
UnpooledUnsafeHeapByteBuf
通过Unsafe函数处理heap读写
protected byte _getByte(int index) {
return UnsafeByteBufUtil.getByte(array, index);
}
//中间省略部分类及代码
static byte getByte(byte[] data, int index) {
return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
}
经过测试通过unsafe方式和普通byte[index]=xxx方式效率上并没有明显差别。
UnpooledDirectByteBuf
相对于UnpooledUnsafeDirectByteBuf,读写缓冲区时直接使用了ByteBuffer自带函数
@Override
protected void _setByte(int index, int value) {
buffer.put(index, (byte) value);
}
ReadOnlyByteBufferBuf
只读缓冲区
@Override
protected void _setByte(int index, int value) {
throw new ReadOnlyBufferException();
}
ReadOnlyUnsafeDirectByteBuf
与UnpooledUnsafeDirectByteBuf一致,只是取消所有写入接口
PooledByteBuf
PooledDirectByteBuf
PooledHeapByteBuf
PooledUnsafeDirectByteBuf
PooledUnsafeHeapByteBuf
这里的缓冲区和Unpooled是对应的,但是使用了Netty4新增的内存池方式,具体下一节再讲,这里就不展开了。
其他类似AbstractDerivedByteBuf的扩展类,都是在已知ByteBuf的基础上在特定场景中使用,比如对已知ByteBuf分片,不同指针重用同一块ByteBuf等,有兴趣同学可以通过源码继续了解,后面有机会也会再写一点这方面的内容。