Netty 中的 ByteBuf 是什么,它和 Java NIO 的 ByteBuffer 有什么区别?

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

释放21集全网最深ConcurrentHashMap的vip视频,复现每一行源码

回答

ByteBuf是Netty 数据传输的载体,是字节缓冲区,用于在 I/O 操作中存储字节数据。在 Netty 中,数据的读写都是以 ByteBuf 为单位进行交互的。

它与 Java NIO 中的 ByteBuffer 存在以下几个区别:

  • 读写索引
    • ByteBuf:提供了两个独立的索引 —— 一个用于读操作的 readerIndex,另一个用于写操作 writerIndex。这使得 ByteBuf 同时进行读写操作变得更加方便,无需在读和写模式之间切换。
    • ByteBuffer:只有一个位置指针,用于读写操作。在进行读写操作切换时需要调用 flip() ,这使得 ByteBuffer 使用起来不如 ByteBuf 灵活。
  • 引用计数
    • ByteBuf:支持引用计数,这是的 ByteBuf 可以更加有效地管理和回收内存。Netty 可以根据引用计数来判断一个 ByteBuf 是否不再被使用,当引用计数为 0 时,它可以被自动释放,这有助于防止内存泄露。
    • ByteBuffer:不支持引用计数,内存管理完全由 JVM 的垃圾回收器负责,这可能会导致内存泄露。
  • 可扩展性和池化
    • ByteBuf:可以根据需要动态调整容量,更加灵活,同时 Netty 还提供了字节缓冲区池,可以重用 ByteBuf 实例,降低内存分配和回收的开销。
    • ByteBuffer:一旦创建,其容量就固定了,不能动态扩展或缩小,而且它不支持池化,在内存使用方面不及 ByteBuf
  • API的用户友好性
    • ByteBuf:提供了更加丰富和友好的 API,使得对其的操作更加容易和直观。
    • ByteBuffer:其 API 相对较为简单和有限,某些操作可能需要更复杂的步骤和更多的代码。

扩展

ByteBuf内部结构

我们首先看 ByteBuf 的内部结构:

从 ByteBuf 的内部结构可以看出,它包含有三个指针:

  • readerIndex:读指针
  • writerIndex:写指针
  • maxCapacity:最大容量

三个指针将整个 ByteBuf 分为四个部分:

  1. 废弃字节:表示已经丢弃的无效字节,我们可以调用 discardReadBytes() 释放这部分空间。
  2. 可读字节:表示可以从 ByteBuf 中读取到的数据,这部分内容等于 writerIndex - readerIndex。readerIndex 随着我们读取 ByteBuf 中的数据而递增,当从 ByteBuf 中读取 N 个字节, readerIndex 就会自增 N,直到 readerIndex = writerIndex 时,就表示 ByteBuf 不可读。
  3. 可写字节:表示可以向 ByteBuf 可写入的字节。writerIndex 也是随着我们向 ByteBuf 中写入数据而自增,当想 ByteBuf 中写入 N 个字节,writerIndex 就会自增 N,当 writerIndex 超过 capacity 时,就需要扩容了。
  4. 可扩容字节:表示 ByteBuf 最多可扩容多少字节 。当向 ByteBuf 写入的数据超过了 capacity 时,就会触发扩容,但是最多可扩容到 maxCapacity ,超过时就会报错。

从这里就可以看出,ByteBuf 很好地解决了原生 NIO ByteBuffer 的不可扩容及读写模式切换的问题。Netty 为什么要设计两个指针呢?主要是为了能够更加高效、更加灵活地处理数据,有两个指针有如下几个优势:

  1. 读写分离:使用两个指针可以将读写两个操作进行有效地分离,而不会相互影响。这使得在同一时间,我们可以在不破坏数据完整性的前提下,进行同时的读取和写入操作。
  2. 更加灵活:两个指针意味着互相独立,我们可以在不影响读指针的情况下,自由地移动写指针,或者在不影响写指针的情况下,自由地移动读指针,这种分离的设计为数据处理提哦乖乖女了更大的灵活性。

ByteBuf 索引变化

清楚了 ByteBuf 的内部结构,我们还需要了解它内部索引的变化情况。

  • 初始分配:这个时候 readerIndex = writerIndex = 0

  • 当我们向 ByteBuf 中写入 N 个字节后,readerIndex = 0,writerIndex = N

  • 当我们从 ByteBuf 中读取 M(M < N)个字节后,readerIndex = M,writerIndex = N

  • 当我们继续往 ByteBuf 中写入数据时ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值