一、ByteBuf与Java NIO Bufferhtml
ByteBuf则是Java NIO Buffer的新轮子,官方列出了一些ByteBuf的特性:java
二、ByteBuf实现类数组
ByteBuf提供了一些较为丰富的实现类,逻辑上主要分为两种:HeapByteBuf和DirectByteBuf,实现机制则分为两种:PooledByteBuf和UnpooledByteBuf,除了这些以外,Netty还实现了一些衍生ByteBuf(DerivedByteBuf),如:ReadOnlyByteBuf、DuplicatedByteBuf以及SlicedByteBuf。app
ByteBuf实现类的类图以下:dom
HeapByteBuf和DirectByteBuf区别在于Buffer的管理方式:HeapByteBuf由Heap管理,Heap是Java堆的意思,内部实现直接采用byte[] array;DirectByteBuf使用是堆外内存,Direct应是采用Direct I/O之意,内部实现使用java.nio.DirectByteBuffoer。性能
PooledByteBuf和UnpooledByteBuf,UnpooledByteBuf实现就是普通的ByteBuf了,PooledByteBuf是4.x以后的新特性,稍后再说。this
DerivedByteBuf是ByteBuf衍生类,实现采用装饰器模式对原有的ByteBuf进行了一些封装。ReadOnlyByteBuf是某个ByteBuf的只读引用;DuplicatedByteBuf是某个ByteBuf对象的引用;SlicedByteBuf是某个ByteBuf的部份内容。.net
SwappedByteBuf和CompositedByteBuf我以为也算某种程度的衍生类吧,SwappedByteBuf封装了一个ByteBuf对象和ByteOrder对象,实现某个ByteBuf对象序列的逆转;CompositedByteBuf内部实现了一个ByteBuf列表,称之为组合ByteBuf,因为不懂相关的技术业务,没法理解该类的存在乎义(官方解释:A user can save bulk memory copy operations using a composite buffer at the cost of relatively expensive random access.)。这两个类从逻辑上彷佛彻底能够继承于DerivedByteBuf,Trustin大神为啥如此设计呢?设计
三、简要的ByteBuf的实现机制指针
ByteBuf有两个指针,readerIndex和writerIndex,用以控制buffer数组的读写。读逻辑较为简单,不考虑边界的状况下,就是`return array[readerIndex++];`。这里简要分析一下HeapByteBuf的读逻辑。
1. AbstractByteBuf.ensureWritable(minWritableBytes);
2. calculateNewCapacity(writerIndex + minWritableBytes)
> 2.1 判断是否超过可写入容量 maxCapacity – writerIndex
> 2.2 超过则抛异常,不然计算新容量 writerIndex + minWritableBytes
> 2.3 判断是否超过设定阈值(4MB),超过每次增长按阈值(4MB)递增,不然
> 2.4 初始大小为64字节(newCapacity),新容量超过newCapacity则翻倍,直到newCapacity大于新容量为止
> 2.5 返回Min(newCapacity, maxCapacity);
3. UnpooledHeapByteBuf.capacity(newCapacity);
> 3.1 确保可访问,有一个`引用计数`的机制,引用计数为0,则抛异常(ensureAccessible)
> 3.2 常规操做:判断是否越界
> 3.3 若是newCapacity比原容量大,则直接建立新数组,并设置。不然
> 3.4 若是readerIndex小于新容量,将readable bytes拷贝至新的数组,反之将readerIndex和writerIndex均设置为newCapacity。
4. setByte(writerIndex++, value)
> 4.1 确保可访问
> 4.2 设置
五、ByteBuf特殊机制
5.1 Pooled
4.x开发了Pooled Buffer,实现了一个高性能的buffer池,分配策略则是结合了buddy allocation和slab allocation的jemalloc变种,代码在io.netty.buffer.PoolArena。暂未深刻研读。
官方说提供了如下优点:
固然,官方也说了不保证没有内存泄露,因此默认状况下仍是采用的UnpooledByteBufAllocator。5.x还处于beta版,看它的「 new and noteworthy 」文档也没说有啥变化,哈哈哈哈,查看最新的「 new and noteworthy 」文档,PooledByteBufAllocator已经设置为默认的Allocator (revised in 2014-01-16)。
5.2 Reference Count
ByteBuf的生命周期管理引入了Reference Count的机制,感受让我回到了CPP时代。能够经过简单的继承SimpleChannelInboundHandler实现自动释放reference count。SimpleChannelInboundHandler的事件方法以下,在消费完毕msg后,能够AutoRelease之:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; messageReceived(ctx, imsg); } else { release = false; ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { ReferenceCountUtil.release(msg); } } }
这一小节能够单独拎出来和Pooled放在一块儿深刻研读研读,有兴趣的能够先看看官方文档: Reference counted objects
5.3 Zero Copy
Zero-copy与传统意义的 zero-copy 不太同样。传统的zero-copy是IO传输过程当中,数据无需中内核态到用户态、用户态到内核态的数据拷贝,减小拷贝次数。而Netty的zero-copy则是彻底在用户态,或者说传输层的zero-copy机制,能够参考下图。因为协议传输过程当中,一般会有拆包、合并包的过程,通常的作法就是System.arrayCopy了,可是Netty经过ByteBuf.slice以及Unpooled.wrappedBuffer等方法拆分、合并Buffer无需拷贝数据。
如何实现zero-copy的呢。slice实现就是建立一个SlicedByteBuf对象,将this对象,以及相应的数据指针传入便可,wrappedBuffer实现机制相似。