Netty-ByteBuf 詳解

Java 中基本類型所佔的字節數

byte     1字節               
short    2字節               
int      4字節               
long     8字節               
char     2字節 可以存儲一個漢字
float    4字節               
double   8字節  

getXXX setXXX不改變指針的操作


public class ByteBufTest002 {
    public static void main(String[] args) {
        ByteBuf byteBuf  = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
        System.out.println(byteBuf.writerIndex());
        for (int i  = 0; i < byteBuf.writerIndex() ; i++){
            byte b = byteBuf.getByte(i);
            System.out.println((char)b + "---------" + byteBuf.readerIndex());
        }
        System.out.println();

        for (int i = 0 ; i < byteBuf.writerIndex(); i++){
            byteBuf.setByte(1,'l');
            System.out.println(byteBuf.writerIndex());
        }
    }
}

執行結果

7
A---------0
B---------0
C---------0
D---------0
E---------0
F---------0
H---------0

7
7
7
7
7
7
7

結論:

get跟set開頭的方法不會改變readerIndex 跟 writerIndex

Buffer中的指針變量跟區域

discardable 被讀過的廢棄掉的

 * <pre>
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * </pre>

可讀字節

public class ByteBufTest003 {
    public static void main(String[] args) {
        ByteBuf byteBuf  = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
        
        //可讀的字節
        while (byteBuf.isReadable()){
            System.out.println((char) byteBuf.readByte() + " ====== " +byteBuf.readerIndex());
        }

        //已經讀完了再讀就會發生異常
        byteBuf.readByte();
    }
}

執行結果

A ====== 1
B ====== 2
C ====== 3
D ====== 4
E ====== 5
F ====== 6
H ====== 7
Exception in thread "main" java.lang.IndexOutOfBoundsException: readerIndex(7) + length(1) exceeds writerIndex(7): UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 7, widx: 7, cap: 21)
	at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1495)
	at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:745)
	at com.clown.netty.bytebuftest.ByteBufTest003.main(ByteBufTest003.java:16)

總結 wirteXXX,readXXX 會改變readerIndex 跟 writerIndex。

可寫字節

/**
 * 可寫字節
 */
public class ByteBufTest004 {
    public static void main(String[] args) {
        ByteBuf byteBuf  = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
        SecureRandom random = new SecureRandom();
        System.out.println("capacity is" + byteBuf.capacity());
        while (byteBuf.writableBytes() > 0 ){
            byteBuf.writeByte(random.nextInt());
            System.out.println(byteBuf.writerIndex());
        }
    }
}

ByteBufAllocator

  1. 獲得ByteBufAllocator
        //通過ChannelHandlerContext
        ByteBufAllocator allocator = channelHandlerContext.alloc();
        ByteBuf buffer = allocator.buffer(16, 32);

        //通過Channel
        ByteBufAllocator allocator1 =  channelHandlerContext.channel().alloc();
        ByteBuf byteBuf2 = allocator1.buffer(32);
        
        //創建DirectByteBuf
        ByteBuf directByteBuf = allocator1.directBuffer(16);

Netty提供了兩種ByteBufAllocator的實現:PooledByteBufAllocator和Unpooled-ByteBufAllocator。前者池化了ByteBuf的實例以提高性能並最大限度地減少內存碎片。

此實現使用了一種稱爲jemalloc的已被大量現代操作系統所採用的高效方法來分配內存,後面是每次都創建一個新的。

雖然Netty默認使用了PooledByteBufAllocator,但這可以很容易地通過Channel-ConfigAPI或者在引導你的應用程序時指定一個不同的分配器來更改。

UnpooledBuffer

名稱 描述
buffer(),
buffer(int capacity),
buffer(int capacity,int maxCapacity)
返回一個未池化得基於堆存儲得ByteBuf
directBuffer()
directBuffer(int initialCapacity)
directBuffer(int initialCapacity, int maxCapacity)
返回一個未被池化的ByteBuf
wrappedBuffer() 返回一個包裝了給定數據的ByteBuf
copiedBuffer() 返回一個複製了給定數據的ByteBuf

clear() 方法 readerIndex 跟writeIndex 都等於 0

 * <pre>
 *  BEFORE clear()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER clear()
 *
 *      +---------------------------------------------------------+
 *      |             writable bytes (got more space)             |
 *      +---------------------------------------------------------+
 *      |                                                         |
 *      0 = readerIndex = writerIndex            <=            capacity
 * </pre>

discardReadBytes()方法對讀寫索引的影響

 * <pre>
 *  BEFORE discardReadBytes()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER discardReadBytes()
 *
 *      +------------------+--------------------------------------+
 *      |  readable bytes  |    writable bytes (got more space)   |
 *      +------------------+--------------------------------------+
 *      |                  |                                      |
 * readerIndex (0) <= writerIndex (decreased)        <=        capacity
 * </pre>

clear() 方法比較的輕量級將兩個指針都指到了零位置上。雖然discardReadBytes 也可以提供新的內存空間來往ByteBuf 來寫數據,但是它會涉及到數據的複製。所以建議使用clear 方法。

ByteBuf 通過兩個指針變量來維護底層讀寫。避免了NIO ByteBuffer的flip() 操作。 並且支持池化,減少內存碎片,也支持堆上分配,跟堆外內存兩種方式,還有複合模式的支持。

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