Netty的ByteBuf是JDK中ByteBuffer的升級(jí)版,提供了NIO buffer和byte數(shù)組的抽象視圖。

ByteBuf的主要類集成關(guān)系:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

(圖片來(lái)自Netty權(quán)威指南,圖中有一個(gè)畫錯(cuò)的地方是PooledByteBuf中的最后一個(gè)子類應(yīng)該是PooledUnsafeDirectByteBuf)


從繼承關(guān)系可以看出AbstractReferenceCountedByteBuf的子類分為兩類:PooledUnpooledByteBuf。

Pooled ByteBuf是基于對(duì)象池的ByteBuf(會(huì)被緩存),Unpooled則是普通的ByteBuf對(duì)象。

無(wú)論是否基于內(nèi)存池的ByteBuf,它的子類有分為DirectByteBuf和HeapByteBuf分別表示在堆外內(nèi)存分配的緩沖區(qū)和在堆內(nèi)存的緩沖區(qū)。

堆內(nèi)存緩沖區(qū)的特點(diǎn)是分配和回收速度快,可以被JVM自動(dòng)回收;缺點(diǎn)是如果進(jìn)行Socket的IO讀寫,需要額外做一次內(nèi)存復(fù)制。

堆外內(nèi)存的緩沖區(qū)相對(duì)于堆內(nèi)存的緩沖區(qū),分配和回收的速度會(huì)慢一些,但是將它寫入或從Socket Channel讀取數(shù)據(jù)是,會(huì)少一次內(nèi)存復(fù)制,速度比堆內(nèi)存更快一些。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

BufferBuf也提供了一類API來(lái)將自己轉(zhuǎn)化成為ByteBuffer以便于在需要ByteBuffer的地方進(jìn)行操作。


AbstractByteBuf

AbstractByteBuf定義了ByteBuf的基礎(chǔ)屬性和一些公用的方法。

主要成員變量有:

readerIndex

writerIndex

markedReaderIndex

markedWriterIndex

maxCapacity

可以看到ByteBuf中分別定義了讀寫游標(biāo),也就是說(shuō)讀游標(biāo)和寫游標(biāo)是分離的,這相對(duì)于ByteBuffer只使用一個(gè)position,在讀寫操作時(shí)會(huì)便利很多。


 大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


一塊緩沖區(qū)會(huì)被兩個(gè)游標(biāo)分隔為三塊區(qū)域,分別是已經(jīng)讀取過(guò)的、可讀的、剩余可寫的。

在寫入數(shù)據(jù)后可以直接開始讀取,不需要flip操作。

 

另外AbstractByteBuf中的方法分為三類:

讀取數(shù)據(jù)、寫入數(shù)據(jù)、操作游標(biāo)

 

讀取操作分為readXXX和getXXX,以讀取Long為例,

readLong()方法在當(dāng)前readerIndex位置讀取8個(gè)Byte并增加readerindex的值;

getLong(int index)則需要接收一個(gè)index參數(shù),從index位置開始讀取8個(gè)Byte,get操作不會(huì)改變r(jià)eaderIndex的值。



寫入操作也有兩類,分別是setXXX和writeXXX,

writeLong(long value)方法在當(dāng)前writerIndex位置開始寫入一個(gè)Long值并增加writerIndex的值;

setLong(int index, long value)方法則接收一個(gè)index參數(shù)作為寫入的位置,寫入操作不修改writerIndex的值。

索引操作就是通過(guò)setReaderIndex之類的方法改變r(jià)eaderIndex的值來(lái)重新讀取數(shù)據(jù),非常簡(jiǎn)單,不做說(shuō)明。


 

AbstractReferenceCountedByteBuf

從類名上看,AbstractReferenceCountedByteBuf主要是實(shí)現(xiàn)了對(duì)引用的計(jì)數(shù),類似于JVM內(nèi)存回收的對(duì)象引用計(jì)數(shù)器,用于跟蹤對(duì)象的分配和銷毀。


大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


只有一個(gè)成員變量:refCnt,看命名也知道是用于計(jì)數(shù)的,并且用AtomicIntegerFieldUpdater來(lái)實(shí)現(xiàn)線程安全的計(jì)數(shù)。 大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

retain API用于增加引用的計(jì)數(shù)。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

release則用于減少計(jì)數(shù)值。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

定義deallocate方法讓子類去實(shí)現(xiàn)當(dāng)引用計(jì)數(shù)為0時(shí)的操作(由子類實(shí)現(xiàn)具體的“回收”操作)。

 


UnpooledHeapByteBuffer

UnpooledHeapByteBuffer是不適用對(duì)象池,且直接在堆內(nèi)存上分配的緩沖區(qū)。 大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


ByteBufAllocator alloc:創(chuàng)建了這個(gè)緩沖區(qū)的分配器

byte[] array:底層存儲(chǔ)

ByteBuffer tmpNioBufNio  ByteBuffer對(duì)象,用于將自身轉(zhuǎn)換成一個(gè)ByteBuffer對(duì)象


大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


構(gòu)造方法非常簡(jiǎn)單

記錄分配器alloc;

初始化數(shù)組;

將讀寫位置調(diào)整為0;


大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這個(gè)構(gòu)造方法則是傳入byte數(shù)組做初始化,writerIndex調(diào)整到數(shù)組后的第一個(gè)位置。

兩個(gè)構(gòu)造方法都有maxCapacity參數(shù),且初始容量要么是initialCapacity要么是initalArray的長(zhǎng)度,說(shuō)明緩沖區(qū)的大小是可以調(diào)整的,最大不超過(guò)maxCapacity。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


通過(guò)capacity來(lái)調(diào)整緩沖區(qū)的大小。如果newCapacity小于當(dāng)前arraylength,那么會(huì)有部分?jǐn)?shù)據(jù)被丟棄。如果newCapacity超過(guò)array的length,那么新擴(kuò)容的位置數(shù)據(jù)未空。

 

UnpooledDirectByteBuf

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


ByteBufAllocator alloc:使用的分配器

ByteBuffer buffer:內(nèi)部用于存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)

ByteBuffer tmpNioBuf:臨時(shí)的ByteBuffer,在將自己轉(zhuǎn)換成ByteBuffer對(duì)象時(shí)會(huì)使用

int capacity:容量

doNotFree:標(biāo)志ByteBuffer是否可以回收


大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

區(qū)別于UnpooledHeapByteBuf,UnpooledDirectByteBuf的擴(kuò)容操作不在是申請(qǐng)數(shù)組進(jìn)行數(shù)據(jù)拷貝,而是申請(qǐng)新的ByteBuffer之后進(jìn)行收拷貝,而ByteBuffer一定是Direct的。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


deallocate實(shí)現(xiàn)了底層存儲(chǔ)ByteBuffer的回收操作,即在引用計(jì)數(shù)為0時(shí)將DirectByteBuffer回收掉(DirectByteBuffer的內(nèi)存是由自己回收的,而不是JVM)。

 

UnpooledUnsafeDirectByteBuf

UnpooledUnsafeDirectByteBufUnpooledUnsafeDirectByteBuf的區(qū)別在于UnpooledUnsafeDirectByteBuf直接使用ByteBuffer來(lái)操作數(shù)據(jù),而UnpooledUnsafeDirectByteBuf采用Unsafe來(lái)操作數(shù)據(jù)。

UnpooledUnsafeDirectByteBuf_getLong實(shí)現(xiàn)

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

UnpooledUnsafeDirectByteBuf_getLong實(shí)現(xiàn):

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)


 

AbstractReferenceCountedByteBuf子類的另一個(gè)分支是PooledByteBuf,即使用對(duì)象池,會(huì)被緩存的ByteBuffer。 

PooledByteBuf有三個(gè)子類:

PooledHeapByteBuf

PooledDirectByteBuf

PooledUnsafeDirectByteBuf

他們分別和Unpooled的幾個(gè)子類對(duì)應(yīng)。

 

對(duì)于Pooled的實(shí)現(xiàn),詳見Netty對(duì)象池實(shí)現(xiàn)分析。

 

歡迎關(guān)注我的個(gè)人公眾號(hào),會(huì)寫一些列關(guān)于消息中間件的文章,也歡迎交流任何技術(shù)問(wèn)題,或者扯扯淡。

http://www.cnblogs.com/hzmark/p/Netty_ByteBuf.html