常见面试题-Netty中ByteBuf类

了解 Netty 中的 ByteBuf 类吗?

答:

在 Java NIO 编程中,Java 提供了 ByteBuffer 作为字节缓冲区类型(缓冲区可以理解为一段内存区域),来表示一个连续的字节序列。

Netty 中并没有使用 Java 的 ByteBuffer,而是使用了新的缓冲类型 ByteBuf,特性如下:

  • 允许自定义缓冲类型

  • 复合缓冲类型中内置的透明的零拷贝实现

  • 开箱即用的动态缓冲类型,具有像 StringBuffer 一样的动态缓冲能力

  • 不再需要调用 flip() 方法

    Java 的 ByteBuffer 类中,需要使用 flip() 来进行读写两种模式的切换

  • 正常情况下具有比 ByteBuffer 更快的响应速度

Java 中的 ByteBuffer:

主要需要注意有 3 个属性:position、limit、capacity

  • capacity:当前数组的容量大小
  • position:写入模式的可写入数据的下标,读取模式的可读取数据下标
  • limit:写入模式的可写入数组大小,读取模式的最多可以读取数据的下标

假如说数组容量是 10,那么三个值初始值为:

position = 0
limit = 10
capacity = 10

假如写入 4 个字节的数据,此时三个值如下:

position = 4
limit = 10
capacity = 10

如果切换到读取数据模式(使用 flip()),会改变上边的三个值,会从 position 的位置开始读取数据到 limit 的位置

position = 0
limit = 4
capacity = 10

Netty 中的 ByteBuf:

ByteBuf 主要使用两个指针来完成缓冲区的读写操作,分别是: readIndexwriteIndex

  • 当写入数据时,writeIndex 会增加
  • 当读取数据时,readIndex 会增加,但不会超过 writeIndex

ByteBuf 的使用:

public static void main(String[] args) {ByteBuf buffer = Unpooled.buffer(10);System.out.println("----------初始化ByteBuf----------");printByteBuffer(buffer);System.out.println("----------ByteBuf写入数据----------");String str = "hello world!";buffer.writeBytes(str.getBytes());printByteBuffer(buffer);System.out.println("----------ByteBuf读取数据----------");while (buffer.isReadable()) {System.out.print((char)buffer.readByte());}System.out.println();printByteBuffer(buffer);System.out.println("----------ByteBuf释放无用空间----------");buffer.discardReadBytes();printByteBuffer(buffer);System.out.println("----------ByteBuf清空----------");buffer.clear();printByteBuffer(buffer);
}
private static void printByteBuffer(ByteBuf buffer) {System.out.println("readerIndex:" + buffer.readerIndex());System.out.println("writerIndex:" + buffer.writerIndex());System.out.println("capacity:" + buffer.capacity());
}
/**输出**/
----------初始化ByteBuf----------
readerIndex:0
writerIndex:0
capacity:10
----------ByteBuf写入数据----------
readerIndex:0
writerIndex:12
capacity:64
----------ByteBuf读取数据----------
hello world!
readerIndex:12
writerIndex:12
capacity:64
----------ByteBuf释放无用空间----------
readerIndex:0
writerIndex:0
capacity:64
----------ByteBuf清空----------
readerIndex:0
writerIndex:0
capacity:64

ByteBuf 的 3 种使用模式:

ByteBuf 共有 3 种使用模式:

  • 堆缓冲区模式(Heap Buffer)

    堆缓冲区模式又称为 “支撑数据”,其数据存放在 JVM 的堆空间

    优点:

    • 数据在 JVM 堆中存储,可以快速创建和释放,并且提供了数组直接快速访问的方法

    缺点:

    • 每次数据与 IO 进行传输时,都需要将数据复制到直接缓冲区(这里为什么要将数据复制到直接缓冲区的原因在上边的 直接内存比堆内存快在了哪里? 问题中已经讲过)

    创建代码:

    ByteBuf buffer = Unpooled.buffer(10);
    
  • 直接缓冲区模式(Direct Buffer)

    直接缓冲区模式属于堆外分配的直接内存,不占用堆的容量

    优点:

    • 使用 socket 传输数据时性能很好,避免了数据从 JVM 堆内存复制到直接缓冲区

    缺点:

    • 相比于堆缓冲区,直接缓冲区分配内存空间和释放更为昂贵

    创建代码:

    ByteBuf buffer = Unpooled.directBuffer(10);
    
  • 复合缓冲区模式(Composite Buffer)

    本质上类似于提供一个或多个 ByteBuf 的组合视图

    优点:

    • 提供一种方式让使用者自由组合多个 ByteBuf,避免了复制和分配新的缓冲区

    缺点:

    • 不支持访问其支撑数据,如果要访问,需要先将内容复制到堆内存,再进行访问

    创建代码:

    public static void main(String[] args) {
    //        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test.class);// 创建一个堆缓冲区ByteBuf heapBuf = Unpooled.buffer(2);String str1 = "hi";heapBuf.writeBytes(str1.getBytes());// 创建一个直接缓冲区ByteBuf directBuf = Unpooled.directBuffer(5);String str2 = "nihao";directBuf.writeBytes(str2.getBytes());// 创建一个复合缓冲区CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer(10);compositeByteBuf.addComponents(heapBuf, directBuf);// 检查是否支持支撑数组,发现并不支持if (!compositeByteBuf.hasArray()) {for (ByteBuf buf : compositeByteBuf) {// 第一个字节偏移量int offset = buf.readerIndex();// 总共数据长度int length = buf.readableBytes();byte[] bytes = new byte[length];// 不支持访问支撑数组,需要将内容复制到堆内存中,即 bytes 数组中,才可以进行访问buf.getBytes(offset, bytes);printByteBuffer(bytes, offset, length);}}
    }private static void printByteBuffer(byte[] array, int offset, int length) {System.out.println("array:" + array);System.out.println("array->String:" + new String(array));System.out.println("offset:" + offset);System.out.println("len:" + length);
    }
    /**输出**/
    array:[B@4f8e5cde
    array->String:hi
    offset:0
    len:2
    array:[B@504bae78
    array->String:nihao
    offset:0
    len:5
    

Netty 中 ByteBuf 如何分配?有池化的操作吗?

答:

ByteBuf 的分配接口定义在了 ByteBufAllocator 中,他的直接抽象类是 AbstractByteBufAllocator,而 AbstractByteBufAllocator 有两种实现:PooledByteBufAllocatorUnpooledByteBufAllocator

在这里插入图片描述

  • PooledByteBufAllocator 提供了池化的操作,将 ByteBuf 实例放入池中,提升了性能,将内存碎片化减到了最小UnpooledByteBufAllocator。(这个实现采用了一种内存分配的高效策略,成为 jemalloc,已经被好几种现代操作系统所采用)
  • UnpooledByteBufAllocator 在每次创建缓冲区时,都会返回一个新的 ByteBuf 实例,这些实例由 JVM 负责 gc 回收

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

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

相关文章

MySQL主从同步延迟原因与解决方案

一、MySQL数据库主从同步延迟产生的原因 MySQL的主从复制都是单线程的操作,主库对所有DDL和DML产生的日志写进binlog,由于binlog是顺序写,所以效率很高。 Slave的SQL Thread线程将主库的DDL和DML操作事件在slave中重放。DML和DDL的IO操作…

08 木谷博客系统RBAC权限设计

这节内容说一下木谷博客系统的权限设计,采用现在主流的权限模型RBAC,对应关系如下: 以上5张表都在mugu_auth_server这个库中 该部分的服务单独定义在user-boot这个模块中。 将角色、权限对应关系加载到Redis 木谷博客系统在认证中心颁发令牌的时候是将用户的角色保存到令牌…

MySQL用得好好的,为何要转ES?

MySQL是一种关系型数据库,它可以高效地存储和查询结构化的数据。 ES是一种分布式搜索引擎,它可以快速地对海量的非结构化或半结构化的数据进行全文检索和分析。 MySQL 和 ES 的数据存储方式也不同。MySQL 中的数据通常是以关系型表的形式存储在磁盘上&…

PTA:百钱买百鸡 - C/C++ 数组及字符串

题目 我国古代数学家张丘建在《算经》一书中提出了下述数学问题: 鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何? 请使用三重或者二重循环求解N块钱买N只鸡的问题:计算并…

EOCR-PFZ数码型产品与控制柜主回路的连接方式

上海韩施电气自动化设备有限公司 施耐德EOCR新一代数码型电动机保护器具有体积小、精度高、抗干扰能力强等特点。为方便安装,EOCR数码型产品与控制柜主回路的连接具有多种方式,分别是:窗口型、贯穿性和端子型。 窗口型(韩施电气…

vue3中shallowReactive与shallowRef

shallowReactive与shallowRef shallowReactive: 只处理了对象内最外层属性的响应式(也就是浅响应式) shallowRef: 只处理了value的响应式, 不进行对象的reactive处理 总结: reactive与ref实现的是深度响应式, 而shallowReactive与shallowRef是浅响应式。 什么时候用浅响应…

Leetcode.974 和可被 K 整除的子数组

题目链接 Leetcode.974 和可被 K 整除的子数组 rating : 1676 题目描述 给定一个整数数组 n u m s nums nums 和一个整数 k k k ,返回其中元素之和可被 k k k 整除的(连续、非空) 子数组 的数目。 子数组 是数组的 连续 部分。 示例 1&…

Kafka的ACK应答级别

在 Kafka 中,ACK(Acknowledgement)应答级别是一个重要的概念,它决定了消息发送到 Kafka 集群后如何确认消息的成功存储。生产者可以根据需要设置不同的 ACK 级别,以在数据可靠性和传输效率之间做出权衡。以下是 Kafka …

万字解析设计模式之观察者模式、中介者模式、访问者模式

一、观察者模式 1.1概述 观察者模式是一种行为型设计模式,它允许一个对象(称为主题或可观察者)在其状态发生改变时,通知它的所有依赖对象(称为观察者)并自动更新它们。这种模式提供了一种松耦合的方式&…

47. QT Android针对Java代码常见接口类型的调用方式总结

1. 说明 在QT中提供了一个接口QAndroidJniObject,可以很方便的对java代码进行调用,但是QT提供的这个类使用起来也并不是很简单,需要根据不同的java接口形式传入不同的参数,比如说在java中定义了一个无参无返回值的接口和一个无参有返回值的接口,又或者定义的还有带参带返…

园区智能配电系统(电力智能监控系统)

园区智能配电系统是一种针对园区电力配送和管理的智能化系统。它的主要功能是实时监控设备运行情况,进行电能质量分析,监控电能损耗,以及分时段用电统计等。 具体来说,园区智能配电系统可以利用现代技术如RS-485总线通信、数据库管…

Android Studio 添加so无法打包进apk问题

1.开发环境: Android Studio 2022.3.1 Patch 2 jdk 17 gradle-7.4 2.build.grade配置检查 首先查看build.gradle中是否设置sourceSets ,如果设置的话,打包的时候so是被指导libs目录下的,所有就不能把jnilibs下。 sourceSets {mai…

计算机视觉面试题-03

1、简单介绍一下sigmoid,relu,softplus,tanh,RBF及其应用场景 这里简单介绍几个激活函数及其应用场景: Sigmoid 函数(Logistic 函数): 公式: s i g m a ( x ) 1 1 e …

硝烟弥漫的科技战场——GPT之战

没想到2023年的双11之后,还能看到如此多的科技圈大佬针对GPT提出火药味十足的讨论和极具戏剧性的表演。 历史回顾: 11月6日,OpenAI发布会:GPT-4 Turbo模型、GPT应用商店、开源Whisper-large-v3等;11月17日&#xff0…

.mallox勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

尊敬的读者: 随着科技的不断发展,互联网的普及,勒索病毒等网络安全威胁也逐渐成为用户和组织面临的严重问题之一。其中,.mallox勒索病毒以其高度破坏性和难以防范的特点引起了广泛关注。本文将介绍.mallox勒索病毒的基本情况&…

2023仿聚合搜索程序源码/轻量级搜狗泛站群程序源码/PHP整站源码+完美SEO优化+符合搜狗算法

源码简介: 2023仿聚合搜索/轻量级搜狗泛站群程序整站源码,作为PHP源码,可以完美SEO优化,符合搜狗搜索引擎算法。 轻量级的PHP搜狗泛站群程序源码,完美SEO优化符合搜狗搜索引擎算法,无需任何采集&#xff…

【Unity细节】为什么加载精灵图集直接导致Unity引擎崩溃

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏:unity细节和bug 😶‍🌫️优质专栏 ⭐【…

创建Dataloader基础篇【一】

概述 在transformers trainer训练、评估模型中,大致根据以下过程加载与处理训练、评估数据集: 使用dataset.Dataset加载数据使用Dataset.map与自定义的convert_examples_to_features函数处理Dataset中的每一行数据定义sampler,在迭代Datalo…

python 实现队列(类似栈实现,采用列表)

队列特点:先进先出 (栈特点:先进后出) 这里依托于 python中的列表,简单实现,由于列表的强大属性,实现循环队列,双队列也很简单,本例进行了一个大概的集中体现 主要实现&#xff0c…

牛客STL练习

链接:https://ac.nowcoder.com/acm/problem/14505 来源:牛客网 题目描述 现在给出一个正方形地图,其边长为n,地图上有的地方是空的,有的地方会有敌人。 我们现在有一次轰炸敌人的机会,轰炸敌人的区域是一个…