一、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實現機制相似。