netty源碼分析(25)- ByteBuf

本節開始學習netty的內存分配機制,搜先是ByteBuf。

作爲一個容器,源碼中的如下。有三塊區域

  • discardable bytes:無效空間(已經讀取過的空間),可丟棄字節的區域,由readerIndex指針控制
  • readable bytes:內容空間,可讀字節的區域,由readerIndexwriterIndex指針控制控制
  • writable bytes:空閒空間,可寫入字節的區域,由writerIndex指針和capacity容量控制
 * <pre>
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * </pre>
  • ByteBuf還定義了抽象方法maxCapacity,用於子類可增加一個最大容量的指針。
    public abstract int maxCapacity();
  • ByteBuf定義了豐富的api,主要是讀寫和設置以及一些指針和容量的操作,詳情參考《ByteBuf 主要API》
  1. 讀邏輯在AbstractByteBuf骨架類,主要就是操作readerIndex指針,而具體怎麼讀着交給具體子類實現,暴露_getByte(i);給子類即可。
    @Override
    public byte readByte() {
        checkReadableBytes0(1);
        int i = readerIndex;
        byte b = _getByte(i);
        readerIndex = i + 1;
        return b;
    }
  1. 寫邏輯在AbstractByteBuf骨架類,把當前的值寫到ByteBuf裏面,擦歐總writerIndex指針,並且暴露_setByte(writerIndex++, value);給子類去具體實現寫邏輯
    @Override
    public ByteBuf writeByte(int value) {
        ensureWritable0(1);
        _setByte(writerIndex++, value);
        return this;
    }
  • ByteBuf分類


  1. pooled和unpooled

Pooled:每次都從預先分配好的內存中去取出一段連續內存封裝成一個ByteBuf給應用程序使用
Unpooled:每次分配內存的時候,直接調用系統api,向操作系統申請一塊內存

  1. Unsafe和非Unsafe

jdk中有Unsafe對象可以直接拿到對象的內存地址,並且基於這個內存地址進行讀寫操作。那麼對應的分類的區別就是是否可以拿到jdk底層的Unsafe進行讀寫操作了。

  1. 跟進PooledUnsafeHeapByteBuf
    @Override
    protected byte _getByte(int index) {
        //memory:內存首地址
        //idx(index):偏移量
        return UnsafeByteBufUtil.getByte(memory, idx(index));
    } 

    static byte getByte(byte[] array, int index) {
        return PlatformDependent.getByte(array, index);
    }

    public static byte getByte(byte[] data, int index) {
        return PlatformDependent0.getByte(data, index);
    }

    static byte getByte(byte[] data, int index) {
        //通過UNSAFE去獲取
        return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
    }
  1. 跟進PooledHeapByteBuf
    @Override
    protected byte _getByte(int index) {
        return HeapByteBufUtil.getByte(memory, idx(index));
    }

    static byte getByte(byte[] memory, int index) {
        //直接拿到一個數組
        return memory[index];
    }
  1. Head和Direct

Head:是調用jvm的堆內存進行分配的,需要被gc進行管理
Direct:是調用jdk的api進行內存分配,不受jvm控制,不會參與到gc的過程

1.跟進UnpooledHeapByteBuf,Head其實就是維持了一個代表內存的數組

    private final ByteBufAllocator alloc;
    //依賴byte數組,所有內存相關的操作都在這.
    //持有內存數組(堆)
    byte[] array;
    private ByteBuffer tmpNioBuf;

    @Override
    protected byte _getByte(int index) {
        //直接傳入內存數組
        return HeapByteBufUtil.getByte(array, index);
    }

    static byte getByte(byte[] memory, int index) {
        //直接拿到一個數組
        return memory[index];
    }

  1. 跟進UnpooledDirectByteBuf,Direct其實就是調用jdk的直接內存對象DirectByteBuffer
import java.nio.ByteBuffer;

    private final ByteBufAllocator alloc;
    //依賴jdk底層的ByteBuffer
    private ByteBuffer buffer;
    private ByteBuffer tmpNioBuf;
    private int capacity;
    private boolean doNotFree;

    @Override
    public byte getByte(int index) {
        ensureAccessible();
        return _getByte(index);
    }

    @Override
    protected byte _getByte(int index) {
        //使用buffer
        return buffer.get(index);
    }

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