netty入门——ByteBuf

创建ByteBuf可以使用ctx.alloc().buffer()方法

直接内存 VS 堆内存

获取直接内存的ByteBuf:ByteBuf buffer = ByteBufAllocator.*DEFAULT*.buffer();

获取堆内存的ByteBuf:ByteBuf buffer2 = ByteBufAllocator.*DEFAULT*.heapBuffer();

  • 直接内存创建和销毁的代价昂贵,但读写性能高(少一次内存复制),适合池化功能一起用
  • 直接内存对GC压力小,因为这部分内存不受JVM垃圾回收的管理,但也要注意及时主动释放

📢 调试日志工具方法

private static void log(ByteBuf byteBuf){
        int length = byteBuf.readableBytes();
        int rows = length / 16 + (length % 15 == 0 ? 0 :1)+4;
        StringBuilder buf = new StringBuilder(rows * 80 * 2)
                .append("read index:").append(byteBuf.readerIndex())
                .append(" write index:").append(byteBuf.writerIndex())
                .append(" capacity:").append(byteBuf.capacity())
                .append(NEWLINE);
        appendPrettyHexDump(buf,byteBuf);
        System.out.println(buf.toString());
    }

池化 VS 非池化

通过配置环境参数:可以把池化功能去除

        Dio.netty.allocator.type=unpooled

池化功能关闭:

UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf :直接内存

UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf :堆内存

池化功能开启:

PooledUnsafeDirectByteBuf :直接内存 PooledUnsafeHeapByteBuf :堆内存

retain & release

Netty中有堆外内存的ByteBuf实现,堆外内存最好是手动释放,

  • UnpooledHeapByteBuf使用的是JVM内存,只需要等GC垃圾回收内存即可
  • UnpoolledDirectByteBuf使用的就是直接内存了,需要特殊的方法来回收内存
  • PooledByteBuf和它的子类使用了池化机制,需要更复杂的规则来回收内存

Nytty采用了引用计数器法来控制回收内存,每个ByteBuf都实现了ReferenceCounted接口

  • 每个ByteBuf对象的初始计数为1
  • 每个ByteBuf方法计数减1,如果计数为0,ByteBuf,ByteBuf内存被回收
  • 调用retain方法计数加1,表示调用者没用完之前,其他handier即使调用了release也不会造成回收
  • 当计数为0时,底层内存会被回收,这时即使ByteBuf对象还在,其各个方法均无法正常使用

调用回收时一般是在最后一个使用ByteBuf的handier使用后调用回收释放内存

        谁是最后使用者,谁负责release

ByteBuf常用方法

方法签名含义备注
writeBoolean(boolean value)写入Boolean值用一字节01
writeByte(int value)写入byte值
writeInt(int value)写入int值Big Endian,即0 * 250,写入后00 00 02 50
writeIntLE(int value)写入int值Little Endian,即0 *250,写入后50 02 00 00
writeBytes(ByteBuf src)写入nio的ByteBuffer
writeCharSequence(CharSequence sequence, Charset charset)写入字符串,需要指明字符集
buffer.readByte()读取一个字节

注意

  • 这些方法的末尾指明返回值的,其返回都是ByteBuf,意味着可以链式调用
    • 网络传输,默认习惯是Bug.endian

slice

【零拷贝】的体现之一,堆原始ByteBuf进行切片成多个ByteBuf,切片后的ByteBuf并没有发生内存复制,还是使用原始ByteBuf的内存,切片后的ByteBuf维护独立的read,write指针

public static void main(String[] args) {
        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(10);
        buf.writeBytes(new byte[]{1,2,3,4,5,6,7,8,9,0});

//        切片过程中,不会发生数据复制
        ByteBuf buf1 = buf.slice(0, 5);
        ByteBuf buf2 = buf.slice(5, 5);
        buf1.setByte(0,'c');
        buf1.retain();
        log(buf1);
        log(buf2);
        buf1.release();
        log(buf);

🐥

  • slice后新的ByteBuf实际使用的还是原来的内存地址,使用如果使用release()后把内存清除掉,即slice()切片后的ByteBuf也无法使用;
  • 切片后的添加元素不能大于切片出来的容量。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值