netty源码分析(25)- ByteBuf

本节开始学习netty的内存分配机制,搜先是ByteBuf。

作为一个容器,源码中的如下。有三块区域

  • discardable bytes:无效空间(已经读取过的空间),可丢弃字节的区域,由readerIndex指针控制
  • readable bytes:内容空间,可读字节的区域,由readerIndexwriterIndex指针控制控制
  • writable bytes:空闲空间,可写入字节的区域,由writerIndex指针和capacity容量控制
 * 
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * 
  • 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分类


    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);
    }

你可能感兴趣的:(netty源码分析(25)- ByteBuf)