【Netty】字节缓冲区 ByteBuf(七)(下)

文章目录

  • 前言
  • 一、实现原理
  • 二、ByteBuf 的使用案例
  • 三、ByteBuf 的3种使用模式
    • 3.1 堆缓冲模式
    • 3.2 直接缓冲区模式
    • 3.3 复合缓冲区模式
  • 总结

前言

回顾Netty系列文章:

  • Netty 概述(一)
  • Netty 架构设计(二)
  • Netty Channel 概述(三)
  • Netty ChannelHandler(四)
  • ChannelPipeline源码分析(五)
  • 字节缓冲区 ByteBuf (六)(上)

在了解了 ByteBuffer 的原理之后,再来理解Netty 的 ByteBuf 就比较简单了。

ByteBuf 是 Netty 框架封装的数据缓冲区,区别于 position、limit、flip等属性和操作来控制 ByteBuffer 的读写,ByteBuf 通过两个位置指针来协助缓冲区的读写操作,分别是readIndex和writeIndex。

readIndex、writeIndex和capacity变量存在以下关系:

0 <= readIndex <= writeIndex <= capacity

一、实现原理

初始化 ByteBuffer 时,readIndex 和 writeIndex 取值一开始都是0。如下图所示:
在这里插入图片描述

当执行写入数据之后,writeIndex会增加,如下图所示:
在这里插入图片描述

当执行读入数据之后则会使readIndex增加,但不会超过writeIndex,如下图:
在这里插入图片描述

在读取之后,索引 0 到 readIndex位置的区域被视为废弃字节(discard)。可以调用discardReadBytes方法,来释放这部分空间,其作用类似于 ByteBuffer的compact()方法,移除无用的数据,实现缓冲区的重复利用。如下图,展示了执行discardReadBytes后的情况,相当于可写的空间变大了。
在这里插入图片描述

二、ByteBuf 的使用案例

为了更好的理解ByteBuf,编写了以下示例:

public class ByteBufDemo {


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 创建一个缓冲区
		ByteBuf buffer = Unpooled.buffer(10);
		System.out.println("------------初始时缓冲区------------");
		printBuffer(buffer);

		// 添加一些数据到缓冲区中
		System.out.println("------------添加数据到缓冲区------------");

		String s = "love";
		buffer.writeBytes(s.getBytes());
		printBuffer(buffer);

		// 读取数据
		System.out.println("------------读取数据------------");

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

		printBuffer(buffer);

		// 执行compact
		System.out.println("------------执行discardReadBytes------------");
		buffer.discardReadBytes();
		printBuffer(buffer);

		// 执行clear
		System.out.println("------------执行clear清空缓冲区------------");
		buffer.clear();
		printBuffer(buffer);

	}

	/**
	 * 打印出ByteBuf的信息
	 * 
	 * @param buffer
	 */
	private static void printBuffer(ByteBuf buffer) {
		System.out.println("readerIndex:" + buffer.readerIndex());
		System.out.println("writerIndex:" + buffer.writerIndex());
		System.out.println("capacity:" + buffer.capacity());
	}
}

输出结果:

-----------初始时缓冲区------------
readerIndex:0
writerIndex:0
capacity:10
------------添加数据到缓冲区------------
readerIndex:0
writerIndex:4
capacity:10
------------读取数据------------
108
111
118
101
readerIndex:4
writerIndex:4
capacity:10
------------执行discardReadBytes------------
readerIndex:0
writerIndex:0
capacity:10
------------执行clear清空缓冲区------------
readerIndex:0
writerIndex:0
capacity:10

Process finished with exit code 0

对比ByteBuffer和ByteBuf两个示例可以看出,Netty 提供了更加方便地创建ByteBuf的工具(unpooled),同时,也不必再执行flip()方法来切换读写模式。对比而言,ByteBuf更加易于使用。

三、ByteBuf 的3种使用模式

ByteBuf 共有三种使用模式:堆缓冲区模式(Heap Buffer)、直接缓冲区模式(Direct Buffer)和 复合缓冲区模式(Composite Buffer)。

3.1 堆缓冲模式

堆缓冲区模式又称为支撑数组,其数据是存放在JVM的堆空间,通过将数据存储在数组中实现。

优点:数据存储在JVM堆中可以快速的创建和快速释放,并且提供了数据快速访问的方法;
缺点:每次数据与 I/O 进行传输时,都需要将数据复制到直接缓冲区。

以下是堆缓冲区的代码示例:

public class ByteBufHeapBufferDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		// 创建一个堆缓冲区
		ByteBuf buffer = Unpooled.buffer(10);
		String s = "waylau";
		buffer.writeBytes(s.getBytes());

		// 检查是否是支撑数组
		if (buffer.hasArray()) {

			// 获取支撑数组的引用
			byte[] array = buffer.array();

			// 计算第一个字节的偏移量
			int offset = buffer.readerIndex() + buffer.arrayOffset();

			// 可读字节数
			int length = buffer.readableBytes();
			printBuffer(array, offset, length);
		}
	}

	/**
	 * 打印出Buffer的信息
	 * 
	 * @param buffer
	 */
	private static void printBuffer(byte[] array, int offset, int len) {
		System.out.println("array:" + array);
		System.out.println("array->String:" + new String(array));
		System.out.println("offset:" + offset);
		System.out.println("len:" + len);
	}
}

输出结果:

array:[B@5b37e0d2
array->String:waylau    
offset:0
len:6

Process finished with exit code 0

3.2 直接缓冲区模式

直接缓冲区属于堆外分配的直接内存,不会占用堆得空间。

优点:使用 socket 传输数据时性能很好,避免了数据从 JVM 堆内存复制到直接缓冲区的过程,提高了性能。
缺点:相对于堆缓冲区而言,直接缓冲区分配内存空间和释放更为昂贵。
对于涉及大量的 I/O 数据的读写,建议使用直接缓冲区。而对于用于后端业务消息编解码模块,建议使用堆缓冲区。
以下是直接缓冲区代码示例:

public class ByteBufDirectBufferDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		// 创建一个直接缓冲区
		ByteBuf buffer = Unpooled.directBuffer(10);
		String s = "waylau";
		buffer.writeBytes(s.getBytes());

		// 检查是否是支撑数组.
		// 不是支撑数组,则为直接缓冲区
		if (!buffer.hasArray()) {

			// 计算第一个字节的偏移量
			int offset = buffer.readerIndex();

			// 可读字节数
			int length = buffer.readableBytes();

			// 获取字节内容
			byte[] array = new byte[length];
			buffer.getBytes(offset, array);

			printBuffer(array, offset, length);
		}
	}

	/**
	 * 打印出Buffer的信息
	 * 
	 * @param buffer
	 */
	private static void printBuffer(byte[] array, int offset, int len) {
		System.out.println("array:" + array);
		System.out.println("array->String:" + new String(array));
		System.out.println("offset:" + offset);
		System.out.println("len:" + len);
	}
}

输出结果:

java复制代码array:[B@6d5380c2
array->String:waylau
offset:0
len:6

Process finished with exit code 0

3.3 复合缓冲区模式

复合缓冲区是 Netty 特有的缓冲区。本质上类似于提供一个或多个 ByteBuf 的组合视图,可以根据需要添加和删除不同类型的 ByteBuf。

优点:提供了一种访问方式让使用者自由地组合多个ByteBuf,避免了复制和分配新的缓冲区。
缺点:不支持访问其支撑数组。因此如果要访问,需要先将内容复制到堆内存中,再进行访问。
以下示例是复合缓冲区将堆缓冲区和直接缓冲区组合在一起,没有进行任何复制过程,仅仅创建了一个视图而已。

public class ByteBufCompositeBufferDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		// 创建一个堆缓冲区
		ByteBuf heapBuf = Unpooled.buffer(3);
		String way = "way";
		heapBuf.writeBytes(way.getBytes());

		// 创建一个直接缓冲区
		ByteBuf directBuf = Unpooled.directBuffer(3);
		String lau = "lau";
		directBuf.writeBytes(lau.getBytes());

		// 创建一个复合缓冲区
		CompositeByteBuf compositeBuffer = Unpooled.compositeBuffer(10);
		compositeBuffer.addComponents(heapBuf, directBuf); // 将缓冲区添加到符合缓冲区

		// 检查是否是支撑数组.
		// 不是支撑数组,则为复合缓冲区
		if (!compositeBuffer.hasArray()) {

			for (ByteBuf buffer : compositeBuffer) {
				// 计算第一个字节的偏移量
				int offset = buffer.readerIndex();

				// 可读字节数
				int length = buffer.readableBytes();

				// 获取字节内容
				byte[] array = new byte[length];
				buffer.getBytes(offset, array);

				printBuffer(array, offset, length);
			}

		}
	}

	/**
	 * 打印出Buffer的信息
	 * 
	 * @param buffer
	 */
	private static void printBuffer(byte[] array, int offset, int len) {
		System.out.println("array:" + array);
		System.out.println("array->String:" + new String(array));
		System.out.println("offset:" + offset);
		System.out.println("len:" + len);
	}
}

输出结果:

array:[B@4d76f3f8
array->String:way
offset:0
len:3
array:[B@2d8e6db6
array->String:lau
offset:0
len:3

Process finished with exit code 0

CompositeByteBuf是一个虚拟的缓冲区,其用途是将多个缓冲区显示为单个合并缓冲区,类似数据库中的视图。

总结

通过以上对于ByteBuf的介绍,相信小伙伴们对于ByteBuf的原理也有了一定的了解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springcloud-alibaba (03)sentinel实现规则持久化-流控规则为例

Sentinel和Nacos的整合可以实现规则动态配置&#xff0c;即在Nacos中修改规则后&#xff0c;Sentinel能够实时地读取并应用新的规则。而规则持久化则是指将规则保存在Nacos中&#xff0c;以避免意外故障或重启时规则被丢失。 实现规则持久化&#xff0c;可以按照以下步骤进行操…

达梦数据库索引的建立使用

达梦数据库支持聚集索引&#xff0c;复合索引&#xff0c;函数索引&#xff0c;唯一索引&#xff0c;位图索引等等。 一.建立索引的准则 1.1在表中插入数据后创建索引 一般情况下&#xff0c;在插入或装载了数据后&#xff0c;为表创建索引会更加有效率。如果在装载数据之前…

进阶篇丨链路追踪(Tracing)很简单:常见问题排查

作者&#xff1a;涯海 经过前面多篇内容的学习&#xff0c;想必大部分同学都已经熟练掌握分布式链路追踪的基础用法&#xff0c;比如回溯链路请求轨迹&#xff0c;定位耗时瓶颈点&#xff1b;配置核心接口黄金三指标告警&#xff0c;第一时间发现流量异常&#xff1b;大促前梳…

电赛E题声源定位跟踪系统制作全过程

声源定位 文章目录 声源定位前言一、题目二、设计步骤1.设计思路2.声源追踪定位的分析3.舵机转角的确定4.声源距离的计算 三、代码编写1.求均值2.卡尔曼滤波 复刻一下电赛的声源定位 前言 2023年的电子设计竞赛快要开始了&#xff0c;同时我也已经大三下了正在准备找工作&…

涨点神器:基于Yolov5/Yolov7的小目标性能提升

1.小目标介绍 目标检测近十年涌现了一大批如Faster R-CNN、RetinaNet、YOLO等可以在工业界实用的目标检测方法,但小目标检测性能差的问题至今也没有被完全解决。因为Swin Transformer的提出,COCO test-dev上的 AP 已经刷到64 ,但小目标检测性能(即APS )和大目标检测性能(…

分享以MM32SPIN0280单片机为主控洗衣机方案

洗衣机是利用电能产生机械作用来洗涤衣物的清洁电器&#xff0c;按驱动方法有3类&#xff0c;直接驱动&#xff0c;皮带驱动&#xff0c;波轮式驱动。 主变一体洗衣机方案以MM32SPIN0280为主控 MCU规格&#xff1a; -ArmCortex-M0内核&#xff0c;最高工作频率可达96MHz -128…

MOSN 基于延迟负载均衡算法——走得更快,期待走得更稳

文&#xff5c;纪卓志&#xff08;GitHub ID&#xff1a;jizhuozhi) 京东高级开发工程师 MOSN 项目 Committer 专注于云原生网关研发的相关工作&#xff0c;长期投入在负载均衡和流量控制领域 前言 这篇文章主要是介绍 MOSN 在 v1.5.0 中新引入的基于延迟的负载均衡算法#2…

【vimsolo】让vim看起来像VSCode:颜色主题和状态栏的配置

文章目录 1. 目的2. 理念&#xff1a; vimsolo3. vimrc: 配置颜色4. vimrc: 配置状态栏5. 拷贝颜色主题和.vimrc: python安装脚本 1. 目的 习惯了 VSCode 默认的配色&#xff1a;黑色主题&#xff0c;蓝色状态栏。偶尔使用 Vim 时想让 vim 伪装的像 VSCode&#xff0c;不考虑花…

float浮点/double双精度浮点和二进制的相互转换,小白也能看明白!

二进制文件包含了太多的数据&#xff0c;如何看懂二进制文件&#xff0c;决定于基础。 文章目录 前言1、重点知识1.1何为二进制文件1.2浮点和双精度的浮点如何生成二进制1.2.1 float和double的基础知识1.2.2 IEEE754约束的重点1.2.3 浮点是如何表示二进制 1.3 例子说明 双精度d…

市面上常见的语音芯片的IO口有哪些作用

语音芯片的IO口有哪些作用&#xff1f; 语音芯片的IO口一般有多种用途&#xff0c;包括以下几种&#xff1a; 1. 语音输入&#xff1a;可以通过外部麦克风接口&#xff0c;将外部声音信号输入到语音芯片中&#xff0c;进行语音信号处理。 2. 语音输出&#xff1a;语音芯片可…

Java版电子招投标系统源码之了解电子招标投标全流程

随着各级政府部门的大力推进&#xff0c;以及国内互联网的建设&#xff0c;电子招投标已经逐渐成为国内主流的招标投标方式&#xff0c;但是依然有很多人对电子招投标的流程不够了解&#xff0c;在具体操作上存在困难。虽然各个交易平台的招标投标在线操作会略有不同&#xff0…

【MySQL】实验十 E-R图

文章目录 1. 学校2. 院系3. 图书馆4. 舰队5. 工厂6. 网购7. IT8. 医院9. 公司1. 学校 设有如下实体: 班主任:工号、姓名、电话 班级:班号、专业、毕业总学分 学生:学号、姓名、性别、年龄 课程:课程号、课程名 上述实体中存在如下联系: (1)一个班主任管理一个班级,一…

字节跳动五面都过了,结果被刷了,问了hr原因竟说是...

摘要 说在前面&#xff0c;面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&#xff0c;最后没offer&#xff0c;自己只想到几个原因&#xff1a;1、虚报工资&#xff0c;比实际高30%&#xff1b;2、有更好的人选&#xff0c;这个可能性不大&…

分布式事务

一、为什么需要分布式事务: 分布式事务是指 会涉及到操作多个数据库(服务)的事务。 其实就是将对 同一数据库&#xff08;服务&#xff09;事务的概念扩大到了多个数据库&#xff08;服务&#xff09;的事务。 目的是为了保证分布式系统中的数据一致性。 二、分布式事务XA规范…

RHCE第五次作业

1.总结变量的类型及含义&#xff1f; 2.实现课堂案例计算长方形面积&#xff1f;&#xff08;6种方式&#xff09; 3.定义变量urlhttps://blog.csdn.net/weixin_45029822/article/details/103568815&#xff08;通过多种方法实现&#xff09; 1&#xff09;截取网站访问的协议 …

如何在华为OD机试中获得满分?Java实现【字母组合】一文详解

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Java华为OD机试真题(2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述4. Java算法源码5. 测试6.解题思路1. 题目描述 每个数字对应多个字母,…

2023年,真的别裸辞....

作为IT行业的大热岗位——软件测试&#xff0c;只要你付出了&#xff0c;就会有回报。说它作为IT热门岗位之一是完全不虚的。可能很多人回说软件测试是吃青春饭的&#xff0c;但放眼望去&#xff0c;哪个工作不是这样的呢&#xff1f;会有哪家公司愿意养一些闲人呢&#xff1f;…

node.js PM2部署项目

文章更新 2023-05-21 更新NSSM安装服务的方式 pm2 是什么 pm2 是一个守护进程管理工具,它能帮你守护和管理你的应用程序。通常一般会在服务上线的时候使用 pm2 进行管理。本文围绕以下重点进行讲解&#xff1a;安装pm2&#xff1b;命令行部署到PM2&#xff1b;PM2查看日志等命…

PLX31-EIP-MBTCP 以太网/IP到Modbus TCP/IP

PLX31-EIP-MBTCP ProSoft Technology的EtherNet/IP to Modbus TCP/IP通信网关允许在支持EtherNet/IP的控制器或设备与Modbus TCP/IP控制器或设备之间进行高速双向数据传输。 我们的Modbus TCP/IP驱动程序具有多种客户端和服务器功能&#xff0c;可实现更快的数据传输。此外&a…

【Linux】普通用户无法使用sudo指令的方法

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…