Netty 5新Buffer API详解

Netty核心包(5.0.0发布版) Netty核心包,5.0.0发布版,包含: netty-all-5.0.0.Alpha1.jar netty-all-5.0.0.Alpha1-sources.jar netty-all-5.0.0.Alpha1-javadoc.jar netty-example-5.0.0.Alpha1.jar netty-example-5.0.0.Alpha1-sources.jar 以及分模块jar包 立即下载

前言

Netty 5的第一个alpha版本于2022/5/17发布。不同于老早发布但后面长期封存的ForkJoinPool版本,这次的新Netty 5改动相对3到4的升级来说没有那么大,侧重点放在了更安全好用的Buffer API和其他一些API的优化上。本文介绍的内容正是这次新版本的重头戏——新的Buffer API。

原API的问题

现存的Netty ByteBuf API已经使用多年,随着时间推移,类库逐渐变得臃肿庞大。导致以下问题:

  1. 它没有利用Java 6之后的新特性,例如try-with-resources。
  2. 太多的实现类和很深的类层次,以至于JIT很难优化,并增加了性能负担。
  3. 需要重新设计与Java新版本匹配的API。为了实现更安全的native内存管理,Java 14提供了MemorySegment功能,以取代原来Unsafe类提供的API。在不久前发布的Java 19中,该功能还处于preview阶段,所以Netty 5也会等正式版发布后再跟进实现,不过新API已经对此做好了设计上的预留。

新API的设计目标

  1. 安全的内存管理。每个buffer都有自己的所有者,不允许其他人破坏与污染。这一点上与MemorySegment API保持一致,因为这也是后者使用的基本要求。
  2. 引导正确使用。用简单的方式引导编码者正确使用Buffer API,减少误用情况。例如将资源放在try-with-resource中管理生命周期。
  3. 让简单的事情保持简单,复杂的事情可以实现。合理的默认值和符合直觉的命名让上手变得容易;同时对于高级使用者来说,也支持高阶的用法不受限制。
  4. 易用的符合直觉的API。需要比老版本更容易使用,工作模型中包含尽量少的隐藏状态。
  5. 高性能。与老版本一样保证API的高性能。

新API的改动

  1. 引用计数:所有buffer实现Autocloseable接口,能够使用try-with-resource来管理。每次buffer的分配都需要对应一次close()的释放,每次Send.receive()也需要对应close()。引用计数不再通过公共API暴露对外,但仍在内部保留,用于计算内存占用(尤其是堆外内存)。现在对外的是open/closed状态,它们的改变不是线程安全的。
 try (Buffer buf = allocator.allocate(8)) {
    // Access the buffer.
} // buf is deallocated here.
  1. 默认开启Cleaner跟踪:老版本的Netty为了性能考虑,默认关闭Cleaner。新版本则是默认开启,好处是:当buffer被忘记关闭时,Cleaner线程会自动回收内存,这样可以避免内存泄漏的发生。

小知识——Java对堆外内存的管理逻辑:

  1. 通过Unsafe分配的堆外内存,只有在Full GC或调用System.gc()时才会回收。
  2. 通过创建DirectByteBuffer分配的堆外内存,会自带一个Cleaner对象,当DirectByteBuffer对象被回收时,会触发Cleaner对象的clean()方法对堆外内存回收。
    在第一种情况下,如果一直不触发Full GC,那么当发生内存泄漏时,内存会逐渐耗尽。(如果在JVM启动参数中设置了最大堆外内存大小,那么达到阈值后也会触发Full GC)
  1. 去掉slice:原来的slice()和duplicate()可以让多个buffer共享同一块内存。现在去除内存共享,让引用计数的规则更加简单。
  2. Buffer接口:原有的ByteBuff抽象类和大量的实现类都被统一的Buffer接口取代;新的Buffer接口只有两种实现,一种基于MemorySegment,一个是CompositeBuffer。通过Buffer接口而非实现类来提供public访问。
  3. Allocator接口:原有的ByteBufAllocator接口被Allocator取代。堆内/堆外、池化/非池化两个维度的不同buffer都通过Allocator的静态工厂方法来分配。下面代码演示了Allocator接口的用法:
try (BufferAllocator allocator = BufferAllocator.heap();
    Buffer buf = allocator.allocate(8)) {
    // Access the buffer.
}
  1. CompositeBuffer:老版本的CompositeByteBuf是对外暴露的类,新版本用CompositeBuffer取代了它,不过大部分方法都隐藏在Buffer接口下。这样做的好处是,不论是组合还是非组合buffer,它们的对外方法都被抽象成一致的,从而避免了许多地方需要对是否为组合buffer做条件判断。另一方面,有些方法是组合buffer特殊的,它们也提供在了CompositeBuffer类中。组合buffer和普通buffer一样,也需要知道它们的allocator,因为在实现ensureWritable()时需要。因此compose()方法需要BufferAllocator作为第一个参数:
try (Buffer x = allocator.allocate(128);
     Buffer y = allocator.allocate(128)) {
    return CompositeBuffer.compose(allocator, x.send(), y.send());
}

通过compose()生成的组合buffer会取得子buffer的所有权。

  1. capacity管理:老版本有capacity()和maxCapacity()两个独立的概念,而且capacity是可以动态修改的。新版本只有capacity(),不再有maxCapacity()。只有ensureWritable()和CompositeBuffer.extendWith()方法可以增加capacity。ensureWritable()需要先获取所有权,否则会抛出异常。write*()方法不再自动增加capacity,若耗尽则会抛出异常。

  2. 字节顺序:老版本的ByteBuf.order(ByteOrder)会返回代表原始buffer视图的新buffer实例,而新版本的Buffer.order(ByteOrder)是直接在原buffer上修改,改变它的访问方法的字节顺序。对比之下,老版本API实现会造成额外的分配和包装buffer的性能开销。为了避免这部分开销,老版本还提供了get/set/read/write*LE()方法,如今也都不需要了。

  3. 用split()切分buffer:老版本的slice()让内存可以共享,但这会带来所有权混乱的问题。新版本用split()来取代,与slice()不同的是,用split()切分后的两个buffer彼此独立,他们各自拥有不同的内存块、capacity、offset和owner。在内存管理中使用了二级引用计数的机制:当切分出来的子buffer都关闭后,原始的buffer也会被关闭。

buf.writeLong(x);
buf.writeLong(y);
executor.submit(new Task(buf.split().send()));
buf.ensureWritable(512);

在上面的例子中,buf被切成两段,一段通过send()传给另一个线程做进一步处理,另一段(原始buf)保留原来的所有者,这使得它能够调用ensureWritable()方法而不会抛出异常。

  1. 用send()转移所有权:之前提到要支持try-with-resource管理buffer生命周期,但这只局限于本线程操作。如果我们需要在另一个线程关闭buffer,就需要显式地把buffer的所有权从一个线程转移到另一个。新版本提供了send()和receive()方法来发送和接收buffer的所有权。这里要注意两点:一是若只调用send()不调用receive(),则buffer最终会被Cleaner回收掉;二是send()会将buffer状态暂时置为不可用,receive()时再恢复状态。下面代码演示了send()和receive()的用法:
var send = buf.send();
executor.submit(() -> {
    try (Buf received = send.receive()) {
        // process received buffer...
    }
});
1448•纯粹素数 纯粹素数是这样定义的:一个素数,去掉最高位,剩下的数仍为素数,再去掉剩下的数的最高位,余下的数还是素数。对于每一个数(无论质数合数)x,筛掉所有小于x最小质因子的质数乘以x的数。但我们知道,我们选择的那个质数必须小于那个合数的最小质因子。p3,因为p2>p1,所以这样是筛不到的。唯一会筛的是第一种:p1和p2*p3。c,s肯定小于刚才那个合数,说明肯定对于它已经筛过,然后a肯定小于s,因为s=b。p3,并且保证p1<p2<p3。我们知道,筛掉这个合数的机会有:p1和p2。c,并且a是最小的因子。 阅读详情

相关推荐

瑞芯微RK3506开发板Ethercat主站性能优化实战:从内核配置到微秒级延迟控制

本文详细介绍了在瑞芯微RK3506开发板上实现EtherCAT主站微秒级延迟控制的实战优化方案。核心在于部署Preempt-RT实时内核,并进行深度系统调优,包括CPU隔离、中断亲和性设置、内存锁定及电源管理调整。通过绕过Linux网络栈的专用驱动加载与配置,最终实现了稳定的高性能实时控制,满足工业自动化需求。

tcp8optimizer的博客 315

深入理解监控系统——CAT Client端源码解析

前言Server端 (Cat-consumer 用于实时分析从客户端提供的数据\Cat-home 作为用户给用户提供展示的控制端 ,并且Cat-home做展示时,通过对Cat-Consumer的调用获取其他节点的数据,将所有数据汇总展示 consumer、home以及路由中心都是部署在一起的,每个服务端节点都可以充当任何一个角色)Client端 (Cat-client 提供给业务以及中间层埋

张硕的博客 1万+

FPGA数字下变频实战:用Vivado DDS IP核实现IQ采样与频率校正(附MATLAB仿真对比)

本文提供了一份基于Vivado DDS IP核实现FPGA数字下变频(DDC)的完整工程指南。详细阐述了IQ采样的原理、DDC链路构建、DDS频率校正的工程实现,并重点介绍了如何利用MATLAB搭建黄金参考模型进行全链路仿真与对比验证,分享了关键的调试技巧与性能优化建议。

t1u2v的博客 810

Netty:一个进阶的门槛

Netty

m0_48159893的博客 1280

3张RTX 4090就能跑!BAGEL-7B多模态模型本地部署避坑指南(附Flash Attention安装技巧)

本文详细介绍了如何在3张RTX 4090显卡上本地部署BAGEL-7B多模态模型,包括硬件配置、环境设置、多卡并行优化及常见问题解决方案。特别提供了Flash Attention安装技巧和显存优化策略,帮助开发者高效运行这一开源多模态模型,实现文本与图像生成任务。

1a2s3d4f5g的博客 652

香橙派rk3588的rknn多线程推理RTSP流服务性能优化与资源分配策略

本文深入探讨了香橙派RK3588平台上的RKNN多线程推理在RTSP流服务中的性能优化与资源分配策略。通过分析硬件架构、设计多线程推理流水线、实现NPU核心负载均衡及优化RGA内存管理,显著提升了RTSP视频流的处理帧率和降低了延迟,为边缘计算视频分析应用提供了实用的优化方案。

7up55的博客 656

Netty5 入门HelloWorld

之前,查找缓冲区泄漏是很困难的,并且泄漏的警告信息也不是很有帮助。的后续版本,因此在架构上进行了一些重大调整,增加了许多新的功能和特性,使得其复杂性相较于。方法返回专门类型的参数,因此你不必在转换他们的返回值。这可以简化你的测试用例代码。的设计方式相似,因此它们之间的差异并不是特别大。中如果存在一个以上的属性容易是多余的。都有其自己的存储用户定义属性的容器。的主要区别在于它们的版本更新以及一些新特性的添加。对于在容器环境下运行的应用是不友好的,现在不是了。的方式,使用该特性需要指定一个用户自定义的。

程序猿进阶 1910

HI3516CV610海思SOC:超高清智慧视觉开发全攻略

本文全面解析海思HI3516CV610 SOC在超高清智慧视觉开发中的应用。该芯片集成双核A7处理器、1Tops NPU、AI ISP及4K视频编码器,专为智能摄像头设计。文章详细介绍了开发环境搭建、核心硬件架构、媒体处理平台(MPP)实战、AI算法集成与系统调优等全流程攻略,帮助开发者高效构建稳定可靠的视觉AI产品。

weixin_29269441的博客 1254

较真儿学源码系列-Netty核心流程源码分析

因为NIO的类库和API比较繁琐,使用起来比较麻烦,开发的工作量和难度都非常大,例如客户端面临断连重连、网络闪断、心跳处理、半包读写、网络拥塞和异常流的处理等等。所以Netty对Java自带的NIO API进行了良好的封装,解决了上述问题。且Netty拥有高性能、吞吐量更高、延迟更低、减少资源消耗、零拷贝直接内存等优点。所以Netty可以很方便地实现出一个网络通信系统,比如聊天服务器或弹幕系统(我曾经使用Netty实现过一个简易聊天室的demo,感兴趣的话可以查看《Netty实现简易聊天室的功能》)。

天瑕的博客 2735

快充协议全兼容!HUSB390对比测试:iPhone/小米/华为哪个充电最快?

本文深入评测了HUSB390快充协议芯片的全兼容性能,展示了其在iPhone、小米和华为设备上的极速充电表现。通过智能功率分配算法和多协议并行处理引擎,HUSB390实现了高效的动态调压和温度控制,显著提升多设备充电效率。特别适合需要同时为不同品牌设备快充的用户。

dd012的博客 1万+

1.嵌入式控制器EC学习,编译环境搭建

工欲善其事,必先利其器。 在学习EC相关知识之前,首先需要完成EC代码编译环境的搭建,需要如下内容: Keil C51(用于EC中C代码的编译器环境) EC源代码,我们使用从网上可以下载到的 ITE_V12.4_Update 版的代码为例进行学习 代码编辑器,这个可以根据自己的习惯选择,VS Code或者Source Insight等 Keil C51下载地址: http://www.downcc.com/soft/307131.html 下载完成后请进行破解 EC源代码 ...

qq_30135687的博客 3917

高性能IO框架Netty五 - Netty内置的编解码器

目录 一、什么是编解码器 二、解码器 2.1ByteToMessageDecoder 2.2MessageToMessageDecoder 2.3 TooLongFrameException 三、编码器 3.1 MessageToByteEncoder 3.2 MessageToMessageEncoder 四、编解码器类 五、Netty内置的编解码器和ChannelH...

b379685397的博客 1万+

【Android面试八股文】Android Application为什么是单例?

这道题相对简单,就是考察大家是否了解application的创建流程。的实例,它用来存储和处理整个全局变量的一些事情,它同时还是一个。为空的时候,才会创建,从而保证了它是一个单例对象。一样有自己的生命周期,但是它并没有那么复杂,因为。对象的创建过程,找出它为什么是单例的原因。全局进行一些配置,比如配置插件。的时候才会创建,所以说可以在。凭什么是单例,我们查看下。启动的时候都会创建一个。是怎么一步步创建的。是一个单例,即每一个。

字节卷动 532

Netty Buffer(缓冲)

正如我们先前所指出的,网络数据的基本单位永远是 byte(字节)。Java NIO 提供 ByteBuffer 作为字节的容器,但这个类是过于复杂,有点 难以使用。 Netty 中 ByteBuffer 替代是 ByteBuf,一个强大的实现,解决 JDK 的 API 的限制,以及为网络应用程序开发者一个更好的工具。 但 ByteBuf 并不仅仅暴露操作一个字节序列的方法;这也是专门的Netty

DavidChen的博客 3026

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Netty从0到1系列之Buffer【上】

Java NIO Buffer是NIO框架中用于数据交互的核心组件,它是一个固定容量的特定数据类型容器,本质上是可读写的内存块。Buffer通过position、limit、capacity三个核心属性控制数据读写位置和边界,支持读写模式切换(使用flip()方法)。Java为各种基本数据类型提供了相应的Buffer实现,其中ByteBuffer最常用。Buffer具有高效的内存管理特性,支持堆内存和直接内存两种实现方式,所有I/O操作都必须通过Buffer进行。

编程技术圈 1449

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Nodyn核心API手册:从Buffer到Crypto模块的全面解析

Nodyn是一个运行在JVM上的Node.js兼容框架,它允许开发者使用Node.js API编写应用程序,同时利用Java虚拟机的强大功能。本手册将全面解析Nodyn的核心API,重点介绍Buffer与Crypto模块的使用方法,帮助开发者快速掌握这两个关键模块的功能和应用场景。 ## Buffer模块:数据处理的基石 Buffer模块是Nodyn中用于处理二进制数据的核心组件,它为开发者提

gitblog_00101的博客 964

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Netty 5用户指南

本文介绍了Netty网络框架的核心功能和使用方法,重点展示了如何利用Netty快速开发自定义协议的网络应用。文章首先指出通用协议(如HTTP)无法满足特定场景需求(如大文件传输、实时消息等)的问题,提出使用Netty可以轻松实现定制化协议。然后通过三个渐进式实例演示Netty的核心功能:1. DISCARD服务(丢弃所有数据的简单协议);2. ECHO服务(请求-响应协议);3. TIME服务(发送时间戳后关闭连接),并详细讲解了客户端实现。文章特别强调了Netty处理TCP流式数据的解决方案

ywl470812087的博客 10万+

netty学习笔记05——buffer的使用

文章目录netty学习笔记05——buffer的使用一个简单的demo netty学习笔记05——buffer的使用 一个简单的demo public class BasicBuffer { public static void main(String[] args) { //创建一个buffer,大小为5,即可以存放5个int IntBuffer intBuffer = IntBuffer.allocate(5); //向buffer中存放数据

qq_22343953的博客 237

Netty基础篇:详解Netty底层NIO

Netty基础篇

七叔的博客 1万+

【一篇入魂】项目从netty3升级netty4之前你需要了解的

Netty3从2016年的3.10.6.Final之后就再没有新版本了,公司项目用的netty3,最近在升级为netty4,下面我们先了解下netty3与netty4的不同之处吧。 项目结构的改变 Netty的包名从 org.jboss.netty 改成 io.netty, 因为 我们不再是JBoss.org的一份子了. 二进制的 JAR 文件被分成多个模块, 这样用户可以从类路径中排除不需要的特...

jiaodaguan的博客 1664

Netty源码解读(二)Netty中的buffer

上一篇文章我们概要介绍了Netty的原理及结构,下面几篇文章我们开始对Netty的各个模块进行比较详细的分析。Netty的结构最底层是buffer模块,这部分也相对独立,我们就先从buffer讲起。 What: buffer二三事 buffer中文名又叫缓冲区,按照维基百科的解释,是”在数据传输时,在内存里开辟的一块临时保存数据的区域”。它其实是一种化同步为异步的机制,可以解决数据传输的速

kobejayandy的专栏 2332

netty原理详解

 NIO客户端序列图步骤一:打开SocketChannel,绑定客户端本地地址(可选,默认系统会随机分配一个可用的本地地址),示例代码如下:1SocketChannel clientChannel = SocketChannel.open();步骤二:设置SocketChannel为非阻塞模式,同时设置客户端连接的TCP参数,示例代码如下:1clientChannel.configureBlock...

七月流星 4993

二、Netty-NIO核心原理详解(NIO核心组件:Buffer、Channel、Selector)

在1.4版本之前,Java IO类库是阻塞式IO;从1.4版本开始,引进了新的异步IO库,被称 为Java New IO类库,简称为Java NIO。Java NIO类库的目标,就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO),称“老的”阻塞式Java IO为OIO(Old IO)。总体上说,NIO弥补了原来面向流的OIO同步阻塞的不足,它为标准Java代码提供了高速的、面向缓冲 区的IO。Java NIO,属于IO 多路复用模型。

洛晓关的博客 1576

Netty源码解读 Netty中的buffer

What: buffer二三事 buffer中文名又叫缓冲区,按照维基百科的解释,是”在数据传输时,在内存里开辟的一块临时保存数据的区域”。它其实是一种化同步为异步的机制,可以解决数据传输的速率不对等以及不稳定的问题。 根据这个定义,我们可以知道涉及I/O(特别是I/O写)的地方,基本会有buffer的存在。就Java来说,我们非常熟悉的Old I/O–InputStream&Outp

u010395804的专栏 843

Java IO演进:从BIO到NIO与Netty,掌握高并发网络编程核心

在计算机系统中,输入输出(IO)是程序与外部世界交互的基础机制,其性能直接影响应用吞吐与响应。IO模型的核心原理在于如何处理数据读写时的等待:传统阻塞IO(BIO)采用同步阻塞方式,每连接独占线程,简单但资源消耗大;而非阻塞IO(NIO)则通过多路复用器(Selector)实现同步非阻塞,单线程可监控大量通道事件,大幅提升并发能力。这一技术价值在于高效利用系统资源,支撑高并发场景,如即时通讯、游戏服务器等。随着分布式架构普及,**Netty**作为基于NIO的异步事件驱动框架,通过Reactor线程模型与P

cuyi7076的博客 525

Netty是什么详解,带案例!(秒懂Netty是什么以及和普通IO的区别)

很多人都不知道Netty是什么,以及跟普通的IO有什么区别,这篇文章就以大白话快速讲解什么是Netty,它是干嘛的。

javaeEEse的博客 772
上一篇: Java热更新失败常见原因总结
下一篇: Java游戏服务器中定时任务的四种实现方式
长三月
博客等级 码龄9年 228粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值