程序猿之路程序员

Netty源码分析(一) ByteBuf

2017-05-22  本文已影响164人  三斤牛肉

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.jpg

ByteBuf可以分为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等,有兴趣同学可以通过源码继续了解,后面有机会也会再写一点这方面的内容。

上一篇下一篇

猜你喜欢

热点阅读