Netty 使用自建的 buffer API,而不是使用 NIO 的 ByteBuffer 來表示一個連續(xù)的字節(jié)序列。與 ByteBuffer 相比這種方式擁有明顯的優(yōu)勢。Netty 使用新的 buffer 類型 ByteBuf,被設計為一個可從底層解決 ByteBuffer 問題,并可滿足日常網絡應用開發(fā)需要的緩沖類型。這些很酷的特性包括:
更多信息請參考:io.netty.buffer 包描述
ByteBuf 具有豐富的操作集,可以快速的實現協議的優(yōu)化。例如,ByteBuf 提供各種操作用于訪問無符號值和字符串,以及在緩沖區(qū)搜索一定的字節(jié)序列。你也可以擴展或包裝現有的緩沖類型用來提供方便的訪問。自定義緩沖式仍然實現自 ByteBuf 接口,而不是引入一個不兼容的類型
舉一個網絡應用到極致的表現,你需要減少內存拷貝操作次數。你可能有一組緩沖區(qū)可以被組合以形成一個完整的消息。網絡提供了一種復合緩沖,允許你從現有的任意數的緩沖區(qū)創(chuàng)建一個新的緩沖區(qū)而無需沒有內存拷貝。例如,一個信息可以由兩部分組成;header 和 body。在一個模塊化的應用,當消息發(fā)送出去時,這兩部分可以由不同的模塊生產和裝配。
<pre> +--------+----------+
| header | body |
+--------+----------+
</pre>
如果你使用的是 ByteBuffer ,你必須要創(chuàng)建一個新的大緩存區(qū)用來拷貝這兩部分到這個新緩存區(qū)中?;蛘?,你可以在 NiO做一個收集寫操作,但限制你將復合緩沖類型作為 ByteBuffer 的數組而不是一個單一的緩沖區(qū),打破了抽象,并且引入了復雜的狀態(tài)管理。此外,如果你不從 NIO channel 讀或寫,它是沒有用的。
// 復合類型與組件類型不兼容。
ByteBuffer[] message = new ByteBuffer[] { header, body };
通過對比, ByteBuf 不會有警告,因為它是完全可擴展并有一個內置的復合緩沖區(qū)。
// 復合類型與組件類型是兼容的。
ByteBuf message = Unpooled.wrappedBuffer(header, body);
// 因此,你甚至可以通過混合復合類型與普通緩沖區(qū)來創(chuàng)建一個復合類型。
ByteBuf messageWithFooter = Unpooled.wrappedBuffer(message, footer);
// 由于復合類型仍是 ByteBuf,訪問其內容很容易,
//并且訪問方法的行為就像是訪問一個單獨的緩沖區(qū),
//即使你想訪問的區(qū)域是跨多個組件。
//這里的無符號整數讀取位于 body 和 footer
messageWithFooter.getUnsignedInt(
messageWithFooter.readableBytes() - footer.readableBytes() - 1);
許多協議定義可變長度的消息,這意味著沒有辦法確定消息的長度,直到你構建的消息?;蛘撸谟嬎汩L度的精確值時,帶來了困難和不便。這就像當你建立一個字符串。你經常估計得到的字符串的長度,讓 StringBuffer 擴大了其本身的需求。
// 一種新的動態(tài)緩沖區(qū)被創(chuàng)建。在內部,實際緩沖區(qū)是被“懶”創(chuàng)建,從而避免潛在的浪費內存空間。
ByteBuf b = Unpooled.buffer(4);
// 當第一個執(zhí)行寫嘗試,內部指定初始容量 4 的緩沖區(qū)被創(chuàng)建
b.writeByte('1');
b.writeByte('2');
b.writeByte('3');
b.writeByte('4');
// 當寫入的字節(jié)數超過初始容量 4 時,
//內部緩沖區(qū)自動分配具有較大的容量
b.writeByte('5');
最頻繁使用的緩沖區(qū) ByteBuf 的實現是一個非常薄的字節(jié)數組包裝器(比如,一個字節(jié))。與 ByteBuffer 不同,它沒有復雜的邊界和索引檢查補償,因此對于 JVM 優(yōu)化緩沖區(qū)的訪問更加簡單。更多復雜的緩沖區(qū)實現是用于拆分或者組合緩存,并且比 ByteBuffer 擁有更好的性能。
更多建議: