Netty4.0源码解析:字节容器UnpooledHeapByteBuf

一、引言

Java NIO提供了ByteBuffer作为字节容器,供Channel读入和写入数据。但ByteBuffer使用过于繁琐,灵活性不够强。Netty实现了ByteBuf来替代JDK的ByteBuffer。
ByteBuf有以下几大优点:
1、它可以被用户自定义的缓冲区类型扩展
2、通过内置的复合缓冲区类型实现了透明的零拷贝
3、容量可以按需增长
4、读写切换无需调用ByteBuffer的filp方法
5、读和写采用了不同的索引
6、支持方法链式调用
7、支持引用计数
8、支持池化

ByteBuf体系结构图:
在这里插入图片描述

ByteBuf常用实现类为:UnpooledHeapByteBuf、UnpooledUnsafeHeapByteBuf、UnpooledDirectByteBuf、UnpooledUnsafeDirectByteBuf。

ByteBuf和JDK的ByteBuffer类似,分为堆缓冲区和直接缓冲区。堆缓冲区直接将数据存储在JVM堆空间中,它能在没有使用池化的情况下快速的分配和释放。直接缓冲区是另外一种ByteBuf模式,它将缓冲区分配在堆外内存(非JVM运行时数据区),垃圾收集器不会管理这部分内存,它的优势在于网络数据传输,但是它的分配和释放都较为昂贵。

我们先从常用的UnpooledHeapByteBuf开始分析ByteBuf:

二、UnpooledHeapByteBuf

UnpooledHeapByteBuf是一个非池化的、内存空间分配在堆的ByteBuf。
实例化UnpooledHeapByteBuf通常是通过Unpooled静态工厂方法buffer,buffer方法有多个重载方法,可以指定缓冲区的初始大小,最大大小:

private static final ByteBufAllocator ALLOC = UnpooledByteBufAllocator.DEFAULT;
public static ByteBuf buffer() {
   
    return ALLOC.heapBuffer();
}
//省略其它重载方法...

Unpooled分配ByteBuf通过默认的ByteBufAllocator:UnpooledByteBufAllocator.DEFAULT进行分配。
UnpooledByteBufAllocator继承了AbstractByteBufAllocator,实现了ByteBufAllocatorMetricProvider接口,它采用单例模式。最终通过newHeapBuffer来实例化UnpooledHeapByteBuf

@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
   
    return PlatformDependent.hasUnsafe() ?
            new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
            new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}

InstrumentedUnpooledUnsafeHeapByteBuf和InstrumentedUnpooledHeapByteBuf是UnpooledByteBufAllocator的内部类,它们分别继承了UnpooledUnsafeHeapByteBuf和UnpooledHeapByteBuf,继承关系如下:
在这里插入图片描述

如果类加载器持有sun.misc.Unsafe,那么默认实例化InstrumentedUnpooledUnsafeHeapByteBuf,对于HotSpot虚拟机来说一般都会实例化这个类。如果没有sun.misc.Unsafe,那么默认实例化InstrumentedUnpooledHeapByteBuf。

InstrumentedUnpooledUnsafeHeapByteBuf和InstrumentedUnpooledHeapByteBuf重写了UnpooledHeapByteBuf的allocateArray方法和freeArray方法。

UnpooledHeapByteBuf持有以下实例变量(包括父类):

//读索引
int readerIndex;
//写索引
int writerIndex;
//标记的读索引
private int markedReaderIndex;
//标记的写索引
private int markedWriterIndex;
//最大缓冲区容量(单位:字节)
private int maxCapacity;
//字节序包装器
private SwappedByteBuf swappedBuf;
//引用计数
private volatile int refCnt;
//缓冲区分配器
private final ByteBufAllocator alloc;
//缓冲区数组
byte[] array;
//临时的JDK ByteBuffer对象
private ByteBuffer tmpNioBuf;
1、构造方法

构造UnpooledHeapByteBuf需要指定一个ByteBuf分配器ByteBufAllocator实例、初始缓冲区大小(单位:字节)、最大缓冲区大小:

public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
   
    super(maxCapacity);
    checkNotNull(alloc, "alloc"); //alloc不能为null
    if (initialCapacity > maxCapacity)
        throw new IllegalArgumentException(String.format(
                "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
    this.alloc = alloc;
    setArray(allocateArray(initialCapacity)); //分配缓冲区
    setIndex(0, 0); //将读索引和写索引设为0
}

1、首先调用父类AbstractReferenceCountedByteBuf的构造方法:

protected AbstractReferenceCountedByteBuf(int maxCapacity) {
   
    super(maxCapacity);
    refCntUpdater.set(this, 1);
}

AbstractReferenceCountedByteBuf持有一个变

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值