Netty之ByteBuf

通過Netty之Helloworld一文,我們簡單的對Netty進行了入門,本文說一下Netty的數據容器ByteBuf。

數據在網絡中是以字節的形式進行傳輸的,JDK的NIO提供了ByteBuffer作爲它的字節容器,然而它使用起來比較繁瑣,例如每次讀寫都需要進行flip等操作,一不小心就會出現錯誤,Netty對其進行了包裝使用ByteBuf作爲其數據容器(底層使用的依舊是ByteBuffer)。

與ByteBuffer相比的兩個優點

與JDK的ByteBuffer相比,ByteBuf主要有以下倆個優點

1.採用讀寫指針,省去flip等操作。

先來看下JDK中的ByteBuffer類,它只有一個位置指針用於處理讀寫操作

其中capacity代表着最大容量,position與limit在讀寫模式下有着不同的含義。當寫數據到buffer時,position會移動到下一個可寫的位置,limit表示最多可以往buffer中寫入多少數據(寫模式下等同於capacity)。當讀時,將position重置爲爲0,positon代表下一個可讀的位置,limit代表最多可以讀取到多少數據 。當由寫切換到讀時,limit會被設置成寫模式下的position。

flip方法的作用就是從寫模式切換到讀模式,將position設爲0,limit設爲寫模式下的position。

再來看Netty的ByteBuf

在抽象類AbstractByteBuf中有以上幾個實例變量,可見ByteBuf通過read與write指針來協助讀寫操作。

0-readerIndex是已經被讀過的字節數,調用discardReadBytes可以釋放這部分空間。readerIndex到writeIndex之間的數據是可以讀取的,writeIndex到capacity是可以寫入的。每次讀寫的時候操作相應的讀寫指針,避免了ByteBuffer的flip模式切換。

2.可自動擴容

在ByteBuffer中,如果在寫入的時候剩餘容量不足,則會出現越界異常,ByteBuf對其進行了優化,類似於HashMap的擴容機制。

每次寫入的時候會調用ensureWritable方法進行容量檢查,最終會調用到ensureWritable0方法

判斷如果寫入的字節數大於最大容量-可寫字節數,則發生越界異常,maxCapacity則用於限制ByteBuf的最大內存大小,能夠有效控制內存容量。接下來看擴容方法

首先判斷寫入的大小是否大於門限值4MB,若大於則採用步增threshold的方式增大newCapacity大小。如果未超過門限值,設初值爲64,然後若還小於寫入大小則進行容量的倍增。總結一下,先倍增然後步增,原理類似於TCP的慢啓動與擁塞避免(參考關於TCP協議的總結)。

ByteBuf的分類

從內存分配角度來看,ByteBuf可以分爲兩類:分配在堆內存的HeapByteBuf與分配在直接內存的DirectByteBuf,前者可以提供快速的分配與釋放,但是在IO讀寫時要額外進行一次內存複製,而後者分配與釋放的代價較昂貴,但是可以實現零拷貝(快速將數據從文件系統移動到網絡接口,而不需要將其從內核空間複製到用戶空間)。一般來說用於IO線程的讀寫緩衝區使用DirectByteBuf較好(Netty即是),其他則使用HeapByteBuf。

從內存回收角度來看,ByteBuf也可分爲兩類:池化PooledByteBuf與普通UnpooledByteBuf,關於池相信不用多說,連接池、線程池相信大家已經很熟了。而且對於池化的bytebuf,Netty使用了引用計數(類似於JVM的引用計數,雖然JVM並不是使用用引用計數法判斷對象是否可以被回收)來降低內存分配的開銷

以上ByteBuf緩衝區的獲取可以通過PooledByteBufAllocator與UnpooledByteBufAllocator來獲取,或者使用工具類Unpooled來方便的獲取未池化的Buffer對象

ByteBuf的操作

讀操作:readXxx()等,表示從buf中讀取相應的字節數。readBytes(xx),表示將當前buf中的數據讀取到目標中。

寫操作:writeXxx()等,表示將參數寫入到當前buf中。writeBytes(xx),表示將目標中的數據寫入到當前buf中。

查找操作:indexOf等,從當前buf中查找相應的value。

置位操作:discard,clear等,主要用於操作ByteBuf內部的讀寫指針。

兩個輔助類

ByteBufHolder:從名字看可以看出,他是持有Bytebuf的容器,在類似HTTP消息的場景下,消息不僅攜帶消息體,還攜帶消息頭,我們就可以實現自己的ByteBufHolder,Netty中相關HTTP的源碼中很多類都實現了這個接口。

CompositeByteBuf:Netty實戰中稱其爲複合緩衝區,它提供了一個將多個緩衝區表示爲一個統一緩衝區的能力。

最後

此致,敬禮。

參考:Netty實戰,Netty權威指南

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章