netty中的ByteBuf

devtools/2025/3/17 8:26:20/

在netty中 ByteBuf是一个高效的缓冲区类,,,它替代了java的nio中的ByteBuffer

ByteBuf 和 ByteBuffer比较

ByteBuffer

  • 读和写共用一个指针,,读写切换的时候,,需要修改指针的位置,
  • 固定的大小,不会自动扩容
    ByteBuff : 是支持动态扩容,,,,他有两个指针,,一个是读指针,一个是写指针,,就不用来回切换读写模式。。。 已经读过的数据叫做废弃部分

ByteBuf分类内存,默认是分配的堆外内存,也就是直接内存,,创建的代价很大,读写的效率很高,因为是零拷贝

堆内存: 创建的效率高,读写效率低

由于ByteBuf一般都使用堆外内存,创建的代价很大,,netty提供了一个池化机制

ByteBuf优势总结:

  1. 池化思想
  2. 读写指针分离,不需要切换模式
  3. 自动扩容
  4. 支持链式调用
  5. 零拷贝: slice duplicate , compositeByteBuf,,
ByteBuf内存回收
  • UnpooledHeapByteBuf ===> 用的堆内存, jvm的gc回收
  • UnpooledDirectByteBuff ===》 用的堆外内存,,可以等gc,也可以显示释放
  • PooledByteBuf ===〉 把ByteBuf占用的内存,归还到内存池中,,后面复用,,池化ByteBuf必须手动释放,否则会内存泄漏

netty使用引用计数(ReferenceCounted)来管理ByteBuf,如果有人使用,就调用retain()方法计数会加1,调用release()方法计数会减1,,当这个计数是0的时候,表示这个ByteBuf是可以回收的

ByteBuf常用方法
  • writeByte()
  • readByte()
  • capacity() : 缓冲区容量
  • readableBytes() : 可读字节数
  • writableBytes()
  • markReaderIndex() : 记录指针位置
  • resetReaderIndex() : 重置指针位置
  • copy() : 复制: 复制不会影响原来的ByteBuf,而是新创一个新的内存,,是内存数据的深拷贝

零拷贝:

  • slice() : 切片: 不会复制数据,而是创建一个ByteBuf共享这个内存
    切片出来的新的ByteBuf不允许往后新增数据,,因为共用的一个内存,指针会出问题
java">	    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,10});//        切片过程中,,没有发生数据复制// 添加新的内容,,会影响别的切片,,所以不允许再往后面添加新的数据,,切面会对最大容量有所限制// 如果对原有的buf进行release,,切片的buf和原始的是同一个内存,,ByteBuf f1 = buf.slice(0, 5);// 让他的引用计数+1,, 释放不掉f1.retain();ByteBuf f2 = buf.slice(5, 5);System.out.println("f1 = " + f1);System.out.println("f2 = " + f2);f1.setByte(0,99);byte aByte = buf.getByte(0);System.out.println(aByte);buf.release();byte aByte1 = f1.getByte(0);System.out.println("aByte1 = " + aByte1);byte aByte2 = f2.getByte(0);System.out.println("aByte2 = " + aByte2);}
  • duplicate() : 复制: 创建一个ByteBuf共享同一个内存
  • composite() : 复合缓冲区: 将小的ByteBuf组合成一个大的ByteBuf,,不会进行数据的拷贝
java">   public static void main(String[] args) {// duplicate// 跟原始的ByteBuf用的同一个内存,,,也是零拷贝// copy 底层内存数据是深拷贝// 将小的ByteBuf 组合成一个 大的ByteBuf ,,也不会进行数据的拷贝ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();buf1.writeBytes(new byte[]{1,2,3,4,5});ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer();buf2.writeBytes(new byte[]{6,7,8,9,10});buf2.retain();CompositeByteBuf buffer = ByteBufAllocator.DEFAULT.compositeBuffer();// 默认不会去调整写入指针位置,,需要设置 自动增长写指针buffer.addComponents(true,buf1,buf2);// 避免释放内存误操作,,需要用retain()添加引用计数buf2.release();System.out.println("buffer = " + buffer);byte aByte = buffer.getByte(9);System.out.println("aByte = " + aByte);}
ByteBuf的工具类 Unpooled

Unpooled.wrappedBuffer() 组合两个ByteBuf

java"> public static void main(String[] args) {// unpooled是一个工具类 : 非池化的ByteBuf 的创建,组合,复制等操作,,,ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();buf1.writeBytes(new byte[]{1,2,3,4,5});ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer();buf2.writeBytes(new byte[]{6,7,8,9,10});// 当ByteBuf超过一个时,,底层使用了compositeByteBufByteBuf buf3 = Unpooled.wrappedBuffer(buf1, buf2);System.out.println("buf3 = " + buf3);byte aByte = buf3.getByte(9);System.out.println("aByte = " + aByte);}

http://www.ppmy.cn/devtools/167771.html

相关文章

C++类的构造与析构:对象生命周期的幕后操控者

目录 一、构造函数:对象诞生的起点 1.1 构造函数的特性 1.2 构造函数的分类与调用 1.3 构造函数初始化列表 二、析构函数:对象生命的终点 2.1 析构函数的特性 2.2 析构函数的作用 2.3 析构函数的调用顺序 三、构造与析构的实际应用与注意事项 3.1 资源管理与内存安…

深度学习基础:线性代数本质6——逆矩阵、列空间与零向量

通过直观的线性变换视角来重新看逆矩阵,列空间,秩,零空间的概念 线性代数在几乎所有领域中都有所体现并被广泛应用的主要原因是:可以帮助我们求解特定的方程组。 1. 矩阵的用途 它能用来描绘对空间的操控,这对计算机…

Suno的对手Luno:AI音乐开发「上传参考音频 - 方式二:通过URL的方式」 —— 「Luno Api系列|AI音乐API」第12篇

导读 今天来看下Luno Api的上传参考音频 - 方式一:通过二进制流的方式。 参考文件,主要是用于在创作的过程中,希望AI参考这个音乐的曲风和声音来进行创作, 这一节看看如何直接使用url的方式进行实现。 申请和使用 「已经有API…

《TypeScript 快速上手:类型、编译与严格模式的简明教程》

一、TypeScript介绍 在引入编程社区 20 多年后,JavaScript 现在已成为有史以来应用最广泛的跨平台语言之一。JavaScript 最初是一种用于向网页添加微不足道的交互性的小型脚本语言,现已发展成为各种规模的前端和后端应 用程序的首选语言。虽然用 JavaSc…

linux命令-wget与curl命令详解

linux命令-wget与curl命令详解 **一、wget 命令详解****1. 基本语法****2. 核心功能****3. 常用选项与示例****示例 1:基本下载****示例 2:自定义输出文件名****示例 3:后台下载****示例 4:断点续传****示例 5:限速下载…

Nest系列:NestJS 中 Logger 完全指南:从基础到企业级实践-04

一、Logger 的核心价值 在服务端应用中,日志系统承担着三大核心职责: 系统监控:实时反馈应用健康状态问题追踪:快速定位异常根源行为审计:记录关键业务操作NestJS 内置的日志系统提供了开箱即用的解决方案,支持: ✅ 多日志级别管理 ✅ 上下文感知日志 ✅ 自定义输出格式…

go数据结构笔记

常用数据结构 切片 定义int类型,大小为3 长度为10 切片的数据结构可以类比成ArrayList,具备动态扩容的数组 package mainimport "fmt"func main() {var numbers make([]int, 3, 10) //切片类型为int 长度为3 容量为10printSlice(numbers)…

CSS块元素、行内元素、行内块元素详解

一、块元素(Block Elements) 1.定义与特点 独占一行:默认情况下,块元素会从新的一行开始,并且其后的元素也会被推到下一行。可设置宽高:可以自由设置宽度(width)和高度&#xff08…