Netty之ByteBuf

版本:4.0.35.Final
netty的ByteBuf结构还是比较多元化的,文章主要学习他的pooled与unpooled,unsafe与非unsafe的内存结构的区别
了解过JDK ByteBuffer的同学应该知道其主要有两种类型,即HeapByteBuffer、MappedByteBuffer(子类就是DirectByteBuffer)。词如其名,一个堆内存一个直接内存(堆外内存)。同样netty也是有同类的对应实现
image.png

堆内内存

UnpooledHeapByteBuf

可以看到构造器中堆内存的申请其实就是一个new byte数组的构建。对于内存的操作也就是直接对byte数组的操作,使用的是HeapByteBufUtil工具类

protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
    this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
}
@Override
public ByteBuf setByte(int index, int value) {
    ensureAccessible();
    _setByte(index, value);
    return this;
}
@Override
protected void _setByte(int index, int value) {
    HeapByteBufUtil.setByte(array, index, value);
}

UnpooledUnsafeHeapByteBuf

该类是非unsafe的子类,继承了大部分的操作,只是操作内存的时候使用的工具类不同,该实现使用的是Unsafe工具类:UnsafeByteBufUtil

UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
    super(alloc, initialCapacity, maxCapacity);
}
@Override
public ByteBuf setByte(int index, int value) {
    checkIndex(index);
    _setByte(index, value);
    return this;
}

@Override
protected void _setByte(int index, int value) {
    UnsafeByteBufUtil.setByte(array, index, value);
}

堆外内存

UnpooledDirectByteBuf

与堆内内存的不同之处在于此处分配内存使用的是jdk nio的ByteBuffer。直接通过ByteBuffer操作内存

protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
    super(maxCapacity);
    ...
    this.alloc = alloc;
    setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
}
@Override
public ByteBuf setByte(int index, int value) {
    ensureAccessible();
    _setByte(index, value);
    return this;
}

@Override
protected void _setByte(int index, int value) {
    buffer.put(index, (byte) value);
}

UnpooledUnsafeDirectByteBuf

堆外内存申请方式与非unsafe方式相同,直接调用jdk nio的ByteBuffer。内存的操作不同是使用UnsafeByteBufUtil工具类

protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
    super(maxCapacity);
    ...
    this.alloc = alloc;
    setByteBuffer(allocateDirect(initialCapacity));
}
protected ByteBuffer allocateDirect(int initialCapacity) {
    return ByteBuffer.allocateDirect(initialCapacity);
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
    UnsafeByteBufUtil.setBytes(this, addr(index), index, src, srcIndex, length);
    return this;
}
@Override
protected void _setByte(int index, int value) {
    UnsafeByteBufUtil.setByte(addr(index), value);
}

工具类

HeapByteBufUtil

堆内内存操作工具类比较直接,直接对byte数组赋值即可

static void setByte(byte[] memory, int index, int value) {
    memory[index] = (byte) value;
}

UnsafeByteBufUtil

写内存操作通过PlatformDependent类调用,PlatformDependent委派PlatformDependent0调用,PlatformDependent0的静态代码块中获取UNSAFE单例,通过UNSAFE操作堆外内存

static void setByte(long address, int value) {
    PlatformDependent.putByte(address, (byte) value);
}
public static void putByte(long address, byte value) {
    PlatformDependent0.putByte(address, value);
}
static void putByte(long address, byte value) {
    UNSAFE.putByte(address, value);
}
public native void putByte(long var1, byte var3);

池化堆内内存

PooledHeapByteBuf

构造器中根据Recycler与最大容量创建当前实例,并将readerIndex、writerIndex、markedReaderIndex、markedWriterIndex归零

private static final Recycler<PooledHeapByteBuf> RECYCLER = new Recycler<PooledHeapByteBuf>() {
    @Override
    protected PooledHeapByteBuf newObject(Handle handle) {
        return new PooledHeapByteBuf(handle, 0);
    }
};
static PooledHeapByteBuf newInstance(int maxCapacity) {
    PooledHeapByteBuf buf = RECYCLER.get();
    buf.reuse(maxCapacity);
    return buf;
}
PooledHeapByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) {
    super(recyclerHandle, maxCapacity);
}
@Override
protected void _setByte(int index, int value) {
    HeapByteBufUtil.setByte(memory, idx(index), value);
}

向内存写数据,写入的是实例变量memory,查看memory的初始化过程,memory是在父类中初始化,初始化有三处调用分别在PoolChunk、PooledUnsafeDirectByteBuf。暂且关注PoolChunk中的init调用。

void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache cache) {
    ...
    memory = chunk.memory;
    ...
}

PoolChunk中初始化调用分别在PoolArena、PoolChunkList、PoolThreadCache。暂且关注PoolArena中的调用。尝试在q050等PoolChunkList中分配,如果失败则添加,创建newChunk内存并初始化,添加至qInit的PoolChunkList,newChunk为抽象方法,PoolArena有俩个子实现类:HeapArena、DirectArena。由于我们此时看的是PooledHeapByteBuf,故暂且关注HeapArena中的实现

private synchronized void allocateNormal(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
        ++allocationsNormal;
    if (q050.allocate(buf, reqCapacity, normCapacity) || q025.allocate(buf, reqCapacity, normCapacity) ||
        q000.allocate(buf, reqCapacity, normCapacity) || qInit.allocate(buf, reqCapacity, normCapacity) ||
        q075.allocate(buf, reqCapacity, normCapacity) || q100.allocate(buf, reqCapacity, normCapacity)) {
        return;
    }

    // Add a new chunk.
    PoolChunk<T> c = newChunk(pageSize, maxOrder, pageShifts, chunkSize);
    long handle = c.allocate(normCapacity);
    assert handle > 0;
    c.initBuf(buf, handle, reqCapacity);
    qInit.add(c);
}

不论是池化还是非池化的Chunk创建都是byte数组的封装,非池化的封装仅需要容量。池化的Chunk则需要更多的属性:pageSize、maxOrder、pageShifts、chunkSize

@Override
protected PoolChunk<byte[]> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) {
    return new PoolChunk<byte[]>(this, new byte[chunkSize], pageSize, maxOrder, pageShifts, chunkSize);
}
@Override
protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
    return new PoolChunk<byte[]>(this, new byte[capacity], capacity);
}

池化堆外内存

PooledUnsafeHeapByteBuf

其父类是PooledHeapByteBuf,区别主要使用了UNSAFE操作内存,其他均一致

@Override
protected void _setByte(int index, int value) {
    UnsafeByteBufUtil.setByte(memory, idx(index), value);
}

PooledDirectByteBuf

初始化过程类似于PooledHeapByteBuf,区别在于PoolArena中创建PoolChunk的newChunk抽象方法的实现类不同,堆外内存使用的DirectArena实现。内存也是使用jdk nio中的ByteBuffer api进行创建。包装的PoolChunk参数也与堆内内存的创建一致

@Override
protected PoolChunk<ByteBuffer> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) {
    return new PoolChunk<ByteBuffer>(
            this, ByteBuffer.allocateDirect(chunkSize), pageSize, maxOrder, pageShifts, chunkSize);
}
@Override
protected PoolChunk<ByteBuffer> newUnpooledChunk(int capacity) {
    return new PoolChunk<ByteBuffer>(this, ByteBuffer.allocateDirect(capacity), capacity);
}

PooledUnsafeDirectByteBuf

类似PooledDirectByteBuf类似,区别在于内存操作使用UNSAFE工具类

Q&A

Unsafe与非Unsafe实现类的应用场景?

池化与非池化的区别?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty中的ByteBuf是一个可扩展的字节容器,它提供了一系列的API来方便地读取和写入字节数据。下面是一些常见的ByteBuf使用API: 1. 创建ByteBuf对象 可以使用Unpooled工具类来创建ByteBuf对象,例如: ```java ByteBuf buf = Unpooled.buffer(10); ``` 上面的代码创建了一个容量为10的ByteBuf对象。 2. 写入数据 可以使用write方法向ByteBuf中写入数据,例如: ```java buf.writeByte(1); buf.writeShort(2); buf.writeInt(3); buf.writeLong(4); buf.writeFloat(5.0f); buf.writeDouble(6.0); buf.writeBytes("hello".getBytes()); ``` 上面的代码依次向ByteBuf中写入了一个字节、一个短整型、一个整型、一个长整型、一个单精度浮点数、一个双精度浮点数和一个字符串。 3. 读取数据 可以使用read方法从ByteBuf中读取数据,例如: ```java byte b = buf.readByte(); short s = buf.readShort(); int i = buf.readInt(); long l = buf.readLong(); float f = buf.readFloat(); double d = buf.readDouble(); byte[] bytes = new byte[5]; buf.readBytes(bytes); String str = new String(bytes); ``` 上面的代码依次从ByteBuf中读取了一个字节、一个短整型、一个整型、一个长整型、一个单精度浮点数、一个双精度浮点数和一个字符串。 4. 获取可读字节数 可以使用可读字节数方法来获取当前ByteBuf中可读的字节数,例如: ```java int readableBytes = buf.readableBytes(); ``` 5. 释放ByteBuf 使用完ByteBuf对象后,需要手动调用release方法释放对象,例如: ```java buf.release(); ``` 上面的代码释放了ByteBuf对象,释放后的ByteBuf不能再被使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值