netty之ByteBuf

Java NIO 提供了 ByteBuffer 作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐。ByteBuf是对java ByteBuffer的封装。

两个索引

在这里插入图片描述

ByteBuf有两个重要的索引,readerIndex和writeIndex。一个用于读取一个用于写入。这两个值初始值都是0。readerIndex用来标识当前读取位置,当从 ByteBuf 读取时,它的 readerIndex 将会被递增已经被读取的字节数。同样地,当写入 ByteBuf 时,它的writerIndex 也会被递增。这两个索引将这弓buf分成三部分。

1、可丢弃部分(Discardable bytes)

0->readerIndex部分。这部分表示已经被读取过的数据,可以被丢弃。

可以通过discardReadBytes清理已读部分数据。

会丢弃0->readerIndex之间的数据。将readerIndex至writerIndex 之间可读部分数据平移至0位置开始。

2、可读部分(Readable bytes)

readerIndex ->writeIndex 之间的部分,也是实际内容区域。任何名称以read或skip开头的操作方法都将获取或跳过当前readerIndex处的数据,并将readerIndex增加之读字节数大小位置。如果没有足够的数据可读,则会抛出IndexOutOfBoundsException异常。可以用isReadable判断是否有可读数据

ByteBuf buffer = ...;while (buffer.isReadable()) {System.out.println(buffer.readByte());}

3、可写部分(Writable bytes)

writeIndex -> capacity 这部分是可以写入数据的部分。所有以write开头的方法都从writeIndex位置开始写入数据,writeIndex增加写入内容字节大小。如果写入数据超过剩余可写容量,则会抛出IndexOutOfBoundsException异常。可以通过maxWritableBytes方法获取剩余可写最大字节数

 ByteBuf buffer = ...;while (buffer.maxWritableBytes() >= 4) {buffer.writeInt(random.nextInt());}

顺序和随机访问索引

顺序访问不指定索引,buf.readByte(),读取后readIndex会递增。

随机访问buf.getByte(i)按索引位置读取数据,不会引起readIndex的变化。

操作示例

//使用Unpooled创建buf
ByteBuf buf = Unpooled.buffer(10);
System.out.println(buf);
for (int i = 0; i < 6; i++) {buf.writeByte(i);//写入数据,writeIndex递增
}
System.out.println(buf);
//随机访问不会改变ridx索引
for (int i = 0; i < 5; i++) {buf.getByte(i);
}
System.out.println(buf);
for (int i = 0; i < 5; i++) {buf.readByte();//顺序读取,readIndex递增
}
//当前最大可写字节大小
System.out.println(buf.maxWritableBytes());
System.out.println(buf);
buf.discardReadBytes();//丢弃已读取数据部分
System.out.println(buf);
/**
输出内容:
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 10)
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 6, cap: 10)
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 6, cap: 10)
2147483641
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 5, widx: 6, cap: 10)
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 1, cap: 10)
**/

内存分配

ByteBuf创建内存区域可以是在JVM内,也可以是直接内存(堆外内存)。如果是堆内存,可以buf.array()获取数据数组,通过buf.hasArray()可以判断是否有数组,间接的可以通过该方法判断是堆内存还是堆外内存。

ByteBuf的分配通过ByteBufAllocator接口进行

在这里插入图片描述

ByteBufAllocator有两个常用的实现类PooledByteBufAllocator和UnpooledByteBufAllocator。一个是buf进行池化另一个非池化。默认情况下DefaultChannelConfig.allocator = ByteBufAllocator.DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR。

来看下ByteBufUtil.DEFAULT_ALLOCATOR的初始化。这一步在ByteBufUtil的静态块里

static {String allocType = SystemPropertyUtil.get("io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");allocType = allocType.toLowerCase(Locale.US).trim();ByteBufAllocator alloc;if ("unpooled".equals(allocType)) {alloc = UnpooledByteBufAllocator.DEFAULT;} else if ("pooled".equals(allocType)) {alloc = PooledByteBufAllocator.DEFAULT;} else {alloc = PooledByteBufAllocator.DEFAULT;}DEFAULT_ALLOCATOR = alloc;//...
}

这里看到默认会读取io.netty.allocator.type配置,如果未设置,判断系统是否是Android,是的化unpooled非池化,否则pooled池化。无论是池化还是非池化创建出来的ByteBuf使用起来都是一样的。

allocator的指定

除了通过配置“io.netty.allocator.type”来指定是allcator。还可以启动时通过配置ChannelOption.ALLOCATOR来指定allcator。

池化意思就像我们的线程池、数据库连接池一样。buf使用完后进行清理,然后放到对象池中可以重复使用。因为buf的创建特别是堆外内存的创建还是相对来说耗时一些。

是否使用堆外内存(dirrect buff)

UnpooledByteBufAllocator.DEFAULT和PooledByteBufAllocator.DEFAULT的创建都会读取PlatformDependent.directBufferPreferred()值用来判断是否使用堆外内存也就是直接内存。

directBufferPreferred的源码:

DIRECT_BUFFER_PREFERRED = CLEANER != NOOP&& !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
public static boolean directBufferPreferred() {return DIRECT_BUFFER_PREFERRED;
}

CLEANER变量赋值逻辑:

if (!isAndroid()) {// only direct to method if we are not running on android.// See https://github.com/netty/netty/issues/2604if (javaVersion() >= 9) {CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;} else {CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;}
} else {CLEANER = NOOP;
}

从上面的逻辑可以看出。要开启堆外内存,首先"io.netty.noPreferDirect"要配置成false,默认就是false。然后jdk支持direct buffer释放的Cleaner。

另外还可以通过Unpooled工具类创建buf。从其名字就可得知创建的非池化buf。

参考:
https://netty.io/4.1/api/io/netty/buffer/ByteBuf.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

adb操作及常用命令

问题&#xff1a;no devices/emulators found&#xff1a;adb devices 没有连接的设备 解决方案&#xff1a; 大概率是因为usb调试功能没有打开&#xff0c;可以查看手机设备是否开启usb调试功能 Android若未开启&#xff0c;可通过设置-关于手机&#xff0c;连续点击版本号7…

小程序自定义导航栏

小程序自定义导航栏&#x1f424;&#x1f424; js data: {statusBarHeight: wx.getSystemInfoSync().statusBarHeight, // 状态栏高度navBarHeight: 44, // 导航栏高度},getSystemInfo() {//获取当前设备信息wx.getSystemInfo({success: res > {// 获取胶囊按钮信息let men…

Linux下的Docker安装,以Ubuntu为例

Docker是一种流行的容器化平台&#xff0c;它能够简化应用程序的部署和管理。 Docker安装 1、检查卸载老版本Docker&#xff08;为保证安装正确&#xff0c;尽量在安装前先进行一次卸载&#xff09; apt-get remove docker docker-engine docker.io containerd runc 2、Dock…

【LeetCode热题100】--15.三数之和

15.三数之和 注意&#xff1a;最后答案中不能包含重复的三元组 使用排序双指针 可以使用三重循环枚举三元组&#xff0c;但是需要哈希表进行去重操作&#xff0c;得到不包含重复三元组的最终答案&#xff0c;消耗量大量的时间和空间 对于不重复的本质&#xff0c;保持三重循环…

malloc是如何实现内存分配的?

文章目录 前言一、malloc实现原理概括&#xff1f;二、brk() 函数与mmap()函数三、mmap实现原理普通读写与mmap对比mmap内存映射实现过程mmap 的适用场景 前言 在C和C中&#xff0c;malloc函数是用于动态分配内存的常用函数。本文将深入探究malloc函数的内存分配实现机制&…

javafx学习记录

1.布局 2.选择重写或实现方法&#xff08;select methods to override/implements&#xff09; ctrl o 3.javafx有init方法,start方法,stop方法 4.定义一个按钮,使用系统默认浏览器访问网站 5.使窗口的关闭栏,缩小扩屏栏,代码是倒数第二行 6.设置模态窗口,默认关闭模态的 下…

9.18号作业

完善登录框 点击登录按钮后&#xff0c;判断账号&#xff08;admin&#xff09;和密码&#xff08;123456&#xff09;是否一致&#xff0c;如果匹配失败&#xff0c;则弹出错误对话框&#xff0c;文本内容“账号密码不匹配&#xff0c;是否重新登录”&#xff0c;给定两个按钮…

Gavin Wood 演讲全文:建设更具韧性以应变化的 Polkadot

我们非常激动能邀请到 Gavin Wood 博士来现场分享关于 Polkadot 的近况以及最新的进展&#xff0c;带来他对于《加密项目应该怎样应对当今世界的变化》的演讲分享。 &#x1f6a9;点击视频链接观看演讲实录&#xff1a;https://www.youtube.com/watch?vYw3mQNJ5UJQ&t1048s…

JWT 使用教程 授权 认证

JWT 1.什么是JWT JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally s…

JDBC基本概念

什么是JDBC JDBC概念 JDBC&#xff08;Java DataBase Connectivity&#xff09;是一套统一的基于Java语言的关系数据库编程接口规范。 该规范允许将SQL语句作为参数通过JDBC接口发送给远端数据库&#xff0c; …

4G模块驱动移植

一、4G模块概述 1、调试的模块型号是广和通的 NL668-EAU-00-M.2。 2、使用的接口是 M.2 Key-B。实际只用到了M2里的USB接口。 调试过程 以QMI_WWAN号方式进行说明&#xff0c;其他拨号方式也试过。最后以QMI_WWAN方式调通了&#xff0c;拨号成功了。 其他拨号方式因为现有文档…

练习敲代码速度

2023年9月18日&#xff0c;周一晚上 今晚不想学习&#xff0c;但又不想玩游戏&#xff0c;于是找了一些练习敲代码的网站来玩玩&#xff0c;顺便练习一下敲代码的速度 目录 参考资料个人推荐第一个 第二个第三个 参考资料 电脑打字慢&#xff0c;有哪些比较好的练打字软件&a…

界面控件DevExpress的VS报表设计器 v23.1——启动速度全面提升

本文主要介绍在DevExpress v23.1这个版本发布周期中对Visual Studio报表设计器所做的改进&#xff0c;包括优化的启动时间、新的全局选项对话框等。 屡获大奖的界面控件套包DevExpress 今年第一个重要版本v23.1正式发布&#xff0c;该版本拥有众多新产品和数十个具有高影响力的…

用无代码搭建数据中台,竟做到如此丝滑

文章目录 需求背景系统介绍配置说明1 菜单导航2 系统自带组件导入页面&#xff08;1&#xff09;数据集成相关组件&#xff08;2&#xff09;数据服务相关组件 3 由系统组件路径添加页面&#xff08;1&#xff09;数据资产管理&#xff08;2&#xff09;数据标准管理&#xff0…

Linux工具(一)

前言&#xff1a;Linux是一个开源的操作系统&#xff0c;它拥有庞大而活跃的开发社区&#xff0c;为用户提供了丰富多样的工具和应用程序。这些工具不仅适用于系统管理员和开发人员&#xff0c;也适用于普通用户&#xff0c;可以帮助他们完成各种任务&#xff0c;从简单的文件管…

题目 1057: 二级C语言-分段函数

有一个函数如下&#xff0c;写一程序&#xff0c;输入x&#xff0c;输出y值。 保留两位小数 样例输入 1 样例输出 1.00 这道题的思路很简单&#xff0c;我直接用if判断输入的X对应的函数Y的区间&#xff0c;代入对应的函数&#xff0c;求出结果。记得变量用浮点型&#xff…

亚马逊云科技面向游戏运营活动的AI生图解决方案

随着Stable Diffusion等AI生图方案逐步普及&#xff0c;越来越多的场景被开发和落地。其中面向游戏C端玩家的AI生图营销活动场景正在被逐步验证&#xff1a;在某个游戏社区中&#xff0c;玩家一键从手机上传一张照片&#xff0c;AI会将自动识别该照片中的元素并替换成游戏中相应…

今年嵌入式行情怎么样?

今年嵌入式行情怎么样&#xff1f; 嵌入式技术今年可以说是IT领域中最炙手可热的之一。随着中年危机和内卷问题的出现&#xff0c;越来越多的互联网从业者将目光投向了嵌入式领域。国内的嵌入式市场一直受终端需求变化的影响而波动&#xff0c;但随着国内产业自主化的发展趋势…

Python匿名函数

简单来说&#xff0c;匿名函数就是懒。 结构 函数名 lambda 参数 : 函数体 fun lambda x,y : x*y*y fun(3,5)优点 可以让写代码更“懒”一点

[S2] Challenge 25 心脏病预测

问题 您是一家医疗保健公司的数据科学家&#xff0c;试图创建患者是否患有心脏病的预测因子。目前&#xff0c;您正在试验 11 种不同的特征&#xff08;潜在心脏病指标&#xff09;和 XGBoost 分类模型&#xff0c;您注意到它的性能可能会根据其调整方式而发生很大变化。在此挑…