美文网首页
netty源码分析(六) - ByteBuf - 1结构

netty源码分析(六) - ByteBuf - 1结构

作者: 进击的蚂蚁zzzliu | 来源:发表于2020-10-14 10:01 被阅读0次

    概述

    netty使用ByteBuf缓冲区来对读写字节进行操作,所谓缓冲区就是可以作为一个字节容器存储字节,等到一定大小之后再交给CPU去处理,提升效率;
    ByteBuf提供了强大的API及体系,相比JDK的ByteBuffer通过position和limit来控制读写,每次切换都需要调用flip方法,ByteBuf通过writerIndex和readerIndex来简化控制,使用简单;

    ByteBuf

    ByteBuf维护了两个索引:readerIndex(读索引)和writerIndex(写索引)

     *      +-------------------+------------------+------------------+
     *      | discardable bytes |  readable bytes  |  writable bytes  |
     *      |                   |     (CONTENT)    |                  |
     *      +-------------------+------------------+------------------+
     *      |                   |                  |                  |
     *      0      <=      readerIndex   <=   writerIndex    <=    capacity
    
    • 通过readerIndex/writerIndex,ByteBuf被分成了三段,数据从左边读取,从右边写入
      1. discardable bytes:废弃区,数据已经被读取(废弃),随时可以清空(把readIndex移动到最左边)
      2. readable bytes:可读区,缓冲区中现存的实际数据,读取数据时readIndex向右移动
      3. writable bytes:可写区,目前是空的,写数据时writerIndex向右移动
    • ByteBuf接口中方法主要分为4类
      1. readxxx:读数据,readIndex向右移动
      2. writexxx:写数据,writerIndex向右移动
      3. setxxx:set数据,readIndex/writerIndex都不移动
      4. markxxx/resetxxx:标记/重置读或写标志位(先标记再进行读写异常回滚)

    ByteBuf分类

    ByteBuf.png
    • ByteBuf有三个维度进行分类:
      1. Pooled/Unpooled:是否使用对象池(默认使用),当对象释放后会归还给对象池,所以可循环使用。当需要大量且频繁创建缓冲区时,建议使用该类缓冲区
      2. Unsafe/非Unsafe:是否使用jdk底层Unsafe对象;
      • Unsafe可以直接通过内存地址+偏移量的方式对内存进行操作(UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index););
      • 非Unsafe直接通过数组下标操作数据(memory[index]);
      • Unsafe/非Unsafe是自动判别的,jdk底层有unsafe对象就分配unsafe否则才分配非unsafe对象
      1. Heap/Direct:Direct直接调用jdkAPI进行分配,不在堆上分配,不归jvm管理,需要手动释放,依赖jdk底层DirectByteBuffer;Heap的底层实现为JAVA堆内的字节数组

    AbstractByteBuf

    AbstractByteBuf是ByteBuf的骨架实现,包含各个读写索引,提供_get/_set方法让子类实现具体的字节操作逻辑;

    //读索引
    int readerIndex;
    //写索引
    int writerIndex;
    //读标记
    private int markedReaderIndex;
    //写标记
    private int markedWriterIndex;
    //最大容量
    private int maxCapacity;
    

    以getInt()和readInt()为例,分析获取数据方法:

    public int getInt(int index) {
        // 检查索引是否越界
        checkIndex(index, 4);   
        return _getInt(index);
    }
    
    public int readInt() {
        // 检查索引是否越界
        checkReadableBytes0(4);
        int v = _getInt(readerIndex);
        // 读索引右移
        readerIndex += 4;   
        return v;
    }
    
    protected abstract int _getInt(int index);  
    

    可见readInt与getInt都是模板方法的模式,先对索引进行检查,然后将实际操作交给子类负责具体实现的_getInt()方法;两者的区别在于是否自动维护读索引,readInt将增加读索引,getInt则不会对索引产生任何影响。

    以setInt()和writeInt()为例,分析写入数据方法

    public ByteBuf setInt(int index, int value) {
        checkIndex(index, 4);
        _setInt(index, value);
        return this;
    }
    
    public ByteBuf writeInt(int value) {
        ensureAccessible();
        ensureWritable0(4);
        _setInt(writerIndex, value);
        writerIndex += 4;
        return this;
    }
    
    protected abstract void _setInt(int index, int value);
    

    ByteBufAllocator(内存分配器)分类

    ByteBufAllocator.png
    • ByteBufAllocator:最顶底层的抽象,负责分配所有类型的内存,包括:buffer/ioBuffer/heapBuffer/directBuffer/compositeBuffer(可以把多个ByteBuf合并成一个,很少使用)
    • AbstractByteBufAllocator:实现了ByteBufAllocator大部分的功能,模板方法中提供了newHeapBuffer/newDirectBuffer两个抽象方法供子类扩展分配不同种类的ByteBuf
    • UnpooledByteBufAllocator:分配不使用内存池的ByteBuf,通过newHeapBuffer方法分配UnpooledUnsafeHeapByteBuf/UnpooledHeapByteBuf;通过newDirectBuffer分配UnpooledUnsafeDirectByteBuf/UnpooledDirectByteBuf;
    • PooledByteBufAllocator:分配使用内存池的ByteBuf,通过newHeapBuffer方法分配PooledUnsafeHeapByteBuf/PooledHeapByteBuf;通过newDirectBuffer分配PooledUnsafeDirectByteBuf/PooledDirectByteBuf;
    • 注意:ByteBuf分类的三个维度:
      1. Pooled/Unpooled:通过不同的子类UnpooledByteBufAllocator/PooledByteBufAllocator区分
      2. Heap/Direct:通过不同分配方法newHeapBuffer/newDirectBuffer区分
      3. Unsafe/非Unsafe:具体分配时通过当前平台是否有Unsafe区分(用户不需要关系)PlatformDependent.hasUnsafe();

    ByteBuf结构分析到此结束,下一节详细讲解各中类型ByteBuf如何分配及重点方法实现

    相关文章

      网友评论

          本文标题:netty源码分析(六) - ByteBuf - 1结构

          本文链接:https://www.haomeiwen.com/subject/sudvpktx.html