在Netty中並無使用Java自帶的ByteBuffer,而是本身實現提供了一個緩存區來用於標識一個字節序列,並幫助用戶操做原始字節或者自定義的POJO。
Java NIO的ByteBuffer問題數組
如上圖,channel與對端的I/O讀寫都要操做Buffers。當有讀操做時,把數據從內核區讀取到用戶區,當有寫操做時,把數據從用戶區寫到內核區。
ByteBuf是Netty的實現的最基本的數據緩衝,它包括Heap Buffer和Direct Buffer。 ByteBuf實現了高級的功能和API,是Java NIO ByteBuffer更高級的封裝和實現。
如上圖是ByteBuf的結構,其中:緩存
當寫入N個數據後,writerIndex向後移動,但要保證writerIndex<capacity,這時可讀數據爲writerIndex,可寫數據長度爲capacity-writerIndex
每讀一個數據,readerIndex向後移動,但readerIndex<=writerIndex,可讀數據writerIndex-readerIndex這時readerIndex-0則是可丟棄的數據段
若是數據繼續寫入緩衝區,而緩存區的writable區間已經被判斷空間不足,那就有兩個方法能夠解決:
動態擴展緩衝區,由ByteBuf實現線程
從新建立一個新的ByteBuffer,並將以前的ByteBuffer複製到新建立的ByteBuffer中,最後釋放老的ByteBuffer3d
重用discard 區域,須要調用discardReadBytes方法指針
Heap Buffer:堆內存字節緩存區,特色是內存的分配和回收速度快,但在I/O讀寫時須要額外一次內存複製,將堆內存對應的緩衝區複製到內核Channel中。
Direct Buffer:直接內存字節緩存區,直接從Socket Channel中讀寫數據,少了一次內存複製,但內存的分配和回收速度慢一些。
Composite Buffer:複合緩衝區,咱們能夠建立多個不一樣的ByteBuf,而後提供一個這些ByteBuf 組合的視圖。複合緩衝區就像一個列表,咱們能夠動態的添加和刪除其中的ByteBuf
ByteBuf擴展了ReferenceCountered接口,這個接口定義的功能主要是引用計數。 經過refCnt的數值來計算ByteBuf,若是refCnt等於1了,調用deallocate來回收ByteBuf,對於池化的ByteBuf則放入內存池,其餘則釋放內存。
Netty使用Recycler來實現輕量級緩衝對象池。
Handlenetty
定義接口code
Stack對象
Stack具體維護着對象池數據,向Recycler提供push和pop兩個主要訪問接口,pop用於從內部彈出一個可被重複使用的對象,push用於回收之後能夠重複使用的對象blog
elements接口
對象池數組
Netty中每一個線程都關聯着一個內存對象池,用來操做緩衝對象
Netty中的I/O操做都須要涉及緩衝區,若是不使用內存池技術,系統將頻繁的建立和回收buffer,對buffer的管理將十分困難。對於HeapBuf和Directbuf都分配和釋放頻率,而且對於Directbuf彌補必定的分配回收代價。
Netty 提供了 CompositeByteBuf 類, 它能夠將多個 ByteBuf 合併爲一個邏輯上的 ByteBuf, 避免了各個 ByteBuf 之間的拷貝
經過 wrap 操做, 咱們能夠將 byte[] 數組、ByteBuf、ByteBuffer等包裝成一個 Netty ByteBuf 對象, 進而避免了拷貝操做
ByteBuf 支持 slice 操做, 所以能夠將 ByteBuf 分解爲多個共享同一個存儲區域的 ByteBuf, 避免了內存的拷貝
經過 channel的tranferTo 實現文件傳輸, 能夠直接將文件緩衝區的數據發送到目標 Channel, 避免了傳統經過循環 write 方式致使的內存拷貝問題.