Netty 4.x – ByteBuf
2019獨角獸企業重金招聘Python工程師標準>>>
1、ByteBuf與Java NIO Buffer
ByteBuf則是Java NIO Buffer的新輪子,官方列出了一些ByteBuf的特性:
- 需要的話,可以自定義buffer類型;
- 通過組合buffer類型,可實現透明的zero-copy;
- 提供動態的buffer類型,如StringBuffer一樣,容量是按需擴展;
- 無需調用flip()方法;
- 常常「often」比ByteBuffer快。
?
2、ByteBuf實現類
ByteBuf提供了一些較為豐富的實現類,邏輯上主要分為兩種:HeapByteBuf和DirectByteBuf,實現機制則分為兩種:PooledByteBuf和UnpooledByteBuf,除了這些之外,Netty還實現了一些衍生ByteBuf(DerivedByteBuf),如:ReadOnlyByteBuf、DuplicatedByteBuf以及SlicedByteBuf。
ByteBuf實現類的類圖如下:
HeapByteBuf和DirectByteBuf區別在于Buffer的管理方式:HeapByteBuf由Heap管理,Heap是Java堆的意思,內部實現直接采用byte[] array;DirectByteBuf使用是堆外內存,Direct應是采用Direct I/O之意,內部實現使用java.nio.DirectByteBuffoer。
PooledByteBuf和UnpooledByteBuf,UnpooledByteBuf實現就是普通的ByteBuf了,PooledByteBuf是4.x之后的新特性,稍后再說。
DerivedByteBuf是ByteBuf衍生類,實現采用裝飾器模式對原有的ByteBuf進行了一些封裝。ReadOnlyByteBuf是某個ByteBuf的只讀引用;DuplicatedByteBuf是某個ByteBuf對象的引用;SlicedByteBuf是某個ByteBuf的部分內容。
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大神為啥如此設計呢?
3、簡要的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 設置
5、ByteBuf特殊機制
5.1 Pooled
4.x開發了Pooled Buffer,實現了一個高性能的buffer池,分配策略則是結合了buddy allocation和slab allocation的jemalloc變種,代碼在io.netty.buffer.PoolArena。暫未深入研讀。
官方說提供了以下優勢:
- 頻繁分配、釋放buffer時減少了GC壓力;
- 在初始化新buffer時減少內存帶寬消耗(初始化時不可避免的要給buffer數組賦初始值);
- 及時的釋放direct buffer。
當然,官方也說了不保證沒有內存泄露,所以默認情況下還是采用的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實現機制類似。
?
?
?
?
?
轉載于:https://my.oschina.net/LucasZhu/blog/1799162
總結
以上是生活随笔為你收集整理的Netty 4.x – ByteBuf的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【python】-- Django 中
- 下一篇: LinkedHashMap的实现原理
