一文讀懂netty對javabytebuf的增強

一、JDKByteBuffer的缺點

1.無法動態擴容:長度是固定,不能動態擴展和收縮,當數據大於ByteBuffer容量時,會發生索引越界異常。

2.API使用複雜:讀寫的時候需要手工調用flip()和rewind()等方法,使用時需要非常謹慎的使用這些api,否則很容易出現錯誤。

二、ByteBuf做的增強方面

1.API操作便捷性

2.動態擴容

3.多種ByteBuf實現

4.高效的零拷貝機制

三、netty中對ByteBuf操作

ByteBuf三個重要的屬性:capacity容量、readerIndex讀取位置、writeindex寫入位置。提供了兩個指針變量來支持順序讀和寫操作,分別爲readerIndex和寫操作writeIndex。

代碼實例:

public class ByteBufDemo {
    @Test
    public void apiTest() {
        //  +-------------------+------------------+------------------+
        //  | discardable bytes |  readable bytes  |  writable bytes  |
        //  |                   |     (CONTENT)    |                  |
        //  +-------------------+------------------+------------------+
        //  |                   |                  |                  |
        //  0      <=       readerIndex   <=   writerIndex    <=    capacity

        // 1.創建一個非池化的ByteBuf,大小爲10個字節
        ByteBuf buf = Unpooled.buffer(10);
        System.out.println("原始ByteBuf爲====================>" + buf.toString());
        System.out.println("1.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 2.寫入一段內容
        byte[] bytes = {1, 2, 3, 4, 5};
        buf.writeBytes(bytes);
        System.out.println("寫入的bytes爲====================>" + Arrays.toString(bytes));
        System.out.println("寫入一段內容後ByteBuf爲===========>" + buf.toString());
        System.out.println("2.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 3.讀取一段內容
        byte b1 = buf.readByte();
        byte b2 = buf.readByte();
        System.out.println("讀取的bytes爲====================>" + Arrays.toString(new byte[]{b1, b2}));
        System.out.println("讀取一段內容後ByteBuf爲===========>" + buf.toString());
        System.out.println("3.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 4.將讀取的內容丟棄
        buf.discardReadBytes();
        System.out.println("將讀取的內容丟棄後ByteBuf爲========>" + buf.toString());
        System.out.println("4.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 5.清空讀寫指針
        buf.clear();
        System.out.println("將讀寫指針清空後ByteBuf爲==========>" + buf.toString());
        System.out.println("5.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 6.再次寫入一段內容,比第一段內容少
        byte[] bytes2 = {1, 2, 3};
        buf.writeBytes(bytes2);
        System.out.println("寫入的bytes爲====================>" + Arrays.toString(bytes2));
        System.out.println("寫入一段內容後ByteBuf爲===========>" + buf.toString());
        System.out.println("6.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");

        // 7.將ByteBuf清零
        buf.setZero(0, buf.capacity());
        System.out.println("將內容清零後ByteBuf爲==============>" + buf.toString());
        System.out.println("7.ByteBuf中的內容爲================>" + Arrays.toString(buf.array()) + "\n");

        // 8.再次寫入一段超過容量的內容
        byte[] bytes3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
        buf.writeBytes(bytes3);
        System.out.println("寫入的bytes爲====================>" + Arrays.toString(bytes3));
        System.out.println("寫入一段內容後ByteBuf爲===========>" + buf.toString());
        System.out.println("8.ByteBuf中的內容爲===============>" + Arrays.toString(buf.array()) + "\n");
}

 四、動態擴容

capacity默認值:256字節、最大值:Integer.MAX_VALUE(2GB);write*方法調用時,通過AbstractByteBuf.ensureWritable()進行檢查。容量計算方法:AbstractByteBufAllocator.calculateNewCapacity(新capacity的最小要求,capacity最大值)根據capacity的最小值要求,對應有兩套計算方法:

          1.沒超過4兆:從64字節開始,每次增加一倍,直至計算出來的newCapacity滿足新容量最小要求。實例:當前大小256,已寫250,繼續寫10字節數據,需要的容量最小要求是261,則新容量是64*2*2*2 = 512。

          2.超過4兆:新容量 = 新容量最小要求/4兆 * 4兆 + 4兆。實例:當前大小3兆,已寫3兆,繼續寫2兆數據,需要的容量最小要求是5兆,則新容量是9兆(不能超過最大值)。

五、豐富的byteBuf實現

netty中根據3個緯度,可以劃分出8中byteBuf的實現:

堆外/堆內 是否池化 訪問方式 具體實現類 備註
heap堆內 unpool safe UnpooledHeapByteBuf 數組實現
unsafe UnpooledUnsafeHeapByteBuf unsafe類直線操作內存
pool safe PooledHeapByteBuf  
unsafe PooledUnsafeHeapByteBuf  
direct堆外 unpool safe UnpooledDirectByteBuf NIO DirectByteBuffer
unsafe UnpooledUnsafeDirectByteBuf  
pool safe PooledDirectByteBuf  
unsafe PooledUnsafeDirectByteBuf  

在使用中,都是通過ByteBufAllocator分配器進行申請,同時分配器具備有內存管理的功能。

六、零拷貝機制

netty的零拷貝機制,是一種應用層的實現。和底層JVM、操作系統內存機制並無過多關聯。

  • CompositeByteBuf,將多個ByteBuf合併爲一個邏輯上的ByteBuf,避免了各個ByteBuf之間的拷貝。

  • wrapedBuffer()方法,將byte[]數組包裝成ByteBuf對象

  • slice()方法。將一個ByteBuf對象切分成多個ByteBuf對象。

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