1. 程式人生 > >Netty in Action (十四) 第五章節 第三部分 ByteBufHolder,ByteBuf分配,計數引用

Netty in Action (十四) 第五章節 第三部分 ByteBufHolder,ByteBuf分配,計數引用

5.4 Interface ByteBufHolder

我們經常在ByteBuf中儲存一些正常資料之外,我們有時候還需要增加一些各式各樣的屬性值,一個Http響應體就是一個很好的例子,除了按照位元組傳輸過來的主體內容,還有狀態碼,cookie等資訊

Netty提供了ByteBufHolder來處理這些常用的使用者案例,ByteBufHolder還提供了Netty一些其他的先進特性,例如快取池,快取池可以是ByteBuf中直接“借出”獲取,如果有需要,“借出”的ByteBuf還可以自動的還到池中

ByteBufHolder提供了一系列的獲取底層資料和引用計數的方法,表5.6向你展示了一些常用的方法

如果你想要實現一個訊息物件可以在ByteBuf中儲存其有效負荷的話,使用ByteBufHolder是一個不錯的選擇

5.5 ByteBuf allocation

在這個小節中,我們將討論管理ByteBuf例項的幾種方法

5.5.1 On-demand: interface ByteBufAllocator

為了減少分配記憶體和釋放記憶體的消耗,Netty用介面ByteBufAllocator來實現了管理池,這個池子可以分配我們定義的任何ByteBuf的例項,管理池的使用是應用程式的具體需求,它不會改變ByteBuf的預設的一些API

表5.7向你展示了ByteBufAllocator提供的一些操作

你可以從一個Channel或者從ChannelHandlerContext中獲取一個ByteBufAllocator的引用,下面的程式碼清單說明了這些方法

Netty提供了ByteBufAllocator介面的兩種具體的實現,PooledByteBufAllocator和UnpooledByteBufAllocator,前者池化儲存ByteBuf來提高效能和減少記憶體碎片的出現,這種方法使用比較出名的高效的“jemalloc”來分配管理記憶體,這種技術已經被用在了目前比較流行的作業系統中了,或者沒有池化儲存ByteBuf的例項,而是每次呼叫返回一個新的例項

Netty預設是使用PooledByteBufAllocator,但是這可以通過修改ChannelConfig或者通過你在專案中bootstrap時指定特定的不同型別來輕易改變這個預設值,詳細的資訊可以參考第八章的內容

5.5.2 Unpooled buffers

在某些情況下,你可能沒有ByteBufAllocator的引用,在這種情況下,Netty提供了一個特殊的類叫Unppoled,它提供了一個靜態的工具方法來創造一個非池化的ByteBuf例項,表5.8展示了Unpooled中比較重要的方法

Unpooled的類也可以使ByteBuf不用於非網路的專案中,使這些專案可以在高效能的可擴充套件的bufferAPI下獲益,並且使用這個不會牽扯到Netty的一些其他的元件

5.5.3 Class ByteBufUtil

ByteBufUtil提供了很多靜態的工具方法來管控ByteBuf,因為ByteBufUtil的API是通用的,與池無關的,這些方法可以被除了分配記憶體的類實現之外,還可以供其他的類使用

在這些靜態方法中最最重要的方法可能就是hexdump方法了,這個方法將ByteBuf包含的內容列印成一個十六進位制的字元,這在很多情形下顯得很是重要,當定位問題和輸出日記的時候,十六進位制的表示比直接獲取byte的值更加友好,還有就是,十六進位制版本的資料可以很輕易地轉回真實的資料格式

另一個有用的方法就是equals的方法了,這個方法可以確認兩個ByteBuf的例項是否相等,如果你實現了你自己的ByteBuf的類的話,你可能會發現ByteBufUtil其他的一些比較有用的方法

5.6 Reference counting

引用計數是一門優化記憶體使用的技術,如果一個物件所持有的資源不再被任何物件引用的時候,將會釋放這部分的資源,Netty在其第四版本為ByteBuf和ByteBufHolder引入了引用計數這項技術,ByteBuf和ByteBufHolder都實現了ReferenceCounted技術

關於引用計數的技術的理論並不是很複雜,大部分情況下它會追蹤一個具體物件被引用的個數,一個實現ReferenceCounted介面的例項一般對一個存活的物件開始計數為1,只要對該物件的引用的個數不是0的情況下,這個物件所持有的資源肯定不會被釋放,當一個存活的物件引用的個數降至0,那麼這個例項將會被釋放,注意,關於"釋放"的明確定義其實並不是很明確,但是至少如果一個物件已經被"釋放",那麼這個物件將不再能夠被使用

引用計數對於池技術的實現是至關重要的,例如PooledByteBufAllocator,這個可以減少記憶體分配的損耗,在下面的兩個程式碼清單中展示了這個例子


如果嘗試獲取一個引用計數的具體物件,但是該物件已經被釋放的時候,會丟擲一個IllegalReferenceCountException的異常

注意一個物件可以在它自己特有的方法中定義它自己的釋放計數的契約,我們可以假設一下它的實現方法release只是設定它的引用計數為0,不管它真實的當前引用計數是多少的時候,這將使這個存活的物件立馬無效變得不合法

WHO IS RESPONSIBLE FOR RELEASE?大體上講,最後一次獲取到該物件的負責釋放它,在第六章中,我們將講解它與它相關聯的ChannelHandler和ChannelPipeline

5.7 Summary

這個章節致力於學習Netty的資料容器,容器都是基於ByteBuf的,我們一開始解釋了ByteBuf的效能為什麼比JDK的高,我們也強調了說明了一個個新的API,並解釋了它們使用的每一個場景

以下,是我們剛剛提及過的:

1)read和write兩個不同的索引控制這我們對資料的操作

2)不同的記憶體使用方法---backing arrays 和 direct buffers

3)可以使用CompositeByteBuf來使多種ByteBuf聚集

4)資料接入的方法:searching,slicing和copying

5)read,write,get和set這些方法的API

6)ByteBufAllocator池和引用計數

在接下來的一個章節中,我們關注的元件是ChannelHandler,它是我們資料處理邏輯的核心關鍵,因為ChannelHandler大類使用ByteBuf,你將開始看到Netty的一些核心元件將被整合在一起被使用