1、ByteBuflinux
下圖是ByteBuf的繼承體系:後端
1、分類api
1)從內存分配角度看,可分爲兩種:網絡
(1)堆內存字節緩衝區:如上圖中帶有Heap的類,它們的特色是直接在堆中分配內存,分配和回收快,但缺點是在網絡通訊讀寫中,需額外作一次內存分配,函數
(2)直接內存緩衝區:使用直接內存進行內存分配,如上圖中帶有Direct的類,它們的特色是分配回收較慢,但網絡通訊中不須要進行額外的內存分配,相似於linux中的sendfile系統調用,它直接將內核緩衝區的數據複製到Channel中,再也不通過用戶緩衝區,由於少了一次複製,性能有所提高。性能
在實際使用中的最佳實踐是在I/O通訊線程的讀寫緩衝區使用直接內存緩衝區,後端業務消息的編解碼使用堆內存緩衝區。線程
2)從內存回收角度看,可分爲兩類:指針
(1)基於對象池的ByteBuf:如繼承體系中帶有Pool的類,它們的內存管理基於對象池,它們本身維護了一個內存池,可提高使用效率。對象
(2)普通ByteBuf繼承
基於對象池的ByteBuf使用時須要更加謹慎。
2、ByteBuf簡介
1)ByteBuf與ByteBuffer的比較
ByteBuf是對NIO中ByteBuffer的封裝,爲何不使用原始的ByteBuffer呢?究其緣由,ByteBuffer有如下不足:
(1):長度固定,一旦分配完成,則容量不能動態擴展或收縮;
(2):讀寫後不方便,由於每次都須要調用flip()等函數處理;
(3):API功能有限,一些高級和實用特性不支持。
2)ByteBuf使用
建立ByteBuf的官方推薦方法是使用Unpool來建立,如:
ByteBuf buf = Unpooled.buffer(20);
相似於ByteBuffer,ByteBuf中也有讀寫索引等概念,不一樣在於ByteBuffer使用一個位置指針處理讀寫操做,而ByteBuffer使用兩個位置指針分別對讀寫進行操做,下圖是ByteBuf的讀寫索引構造:
其中readerIndex標識讀取索引,writerIndex標識寫索引,capacity爲容量,即readerIndex到writerIndex部分是可讀部分,writerIndex到capacity部分是可寫部分。
discardable bytes部分是可重用部分,這時咱們可調用相應的api重用該部份內存來增長可寫內存,如調用discardReadBytes()方法則會將writerIndex置爲writerIndex – readerIndex,readerIndex置爲0,同時發生數據的複製,即將原來可讀的內容向前移動,因此頻繁調用該函數將致使性能的降低。下圖是調用discardReadBytes先後的對比圖:
一種更好的方法是調用clear()函數,這樣不會致使內存的移動,它僅僅是移動了位置指針,不過會致使可讀內容的晴空,下圖是調用clear函數先後的狀況:
ByteBuf中也一樣支持ByteBuffer中的mark和reset操做,不過更加豐富,它支持如下四個函數:
(1)markReaderIndex
(2)markWriterIndex
(3)resetReaderIndex
(4)resetWriterIndex
ByteBuf中有Derived buffer的概念,ByteBuf提供了接口用於實現ByteBuf的複製,如如下方法:
(1)duplicate:返回當前ByteBuf的複製對象,但返回的ByteBuf對象與原始的ByteBuf共享緩衝區內容,即更改返回後ByteBuf的內容一樣也會更改原始的ByteBuf中的內容,返回後的ByteBuf會維護本身獨立的讀寫索引;
(2)copy:複製一個新的ByteBuf,與duplicate不一樣的是,返回後的ByteBuf在內容上是獨立的。還有copy(int index, int length),從字面上也很好理解;
(3)slice:返回當前ByteBuf的可讀子緩衝區,起始位置從readerIndex到writerIndex,返回後的ByteBuf與原ByteBuf共享內容,但讀寫索引地理維護。
ByteBuf還可轉換成標準的ByteBuffer,主要使用兩個方法:
nioBuffer():將當前ByteBuf的可讀緩衝區轉換成ByteBuffer,但二者共享同一緩衝區內容。
nioBuffer(int index, int length):將當前ByteBuf從index開始長度爲length的緩衝區轉換成ByteBuffer。
ByteBuf支持一系列的隨機讀寫操做,它們是一系列set和get操做,具體見API。