netty4报错:io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
背景:netty执行链中有一串自定义的handler,目前我想要在中间再加上一个pingPonghandler来进行控制帧的处理,从而避免ng的读写超时(客户要求,与他们建立的通道一直连接,不进行断连,从而需要考虑ng的问题);
当我添加如下代码后报错:io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1,ByteBuf 的引用计数refCnt为0;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame; public class PingPongHandler extends SimpleChannelInboundHandler<WebSocketFrame> { @Override protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { if (frame instanceof PingWebSocketFrame) { // 接收到PING帧 System.out.println("Received PING frame"); // 发送PONG帧作为响应 ctx.channel().writeAndFlush(new PongWebSocketFrame(Unpooled.buffer(0))); } else if (frame instanceof PongWebSocketFrame) { // 接收到PONG帧 System.out.println("Received PONG frame"); } else { // 其他类型的帧,继续传递给下一个处理器 ctx.fireChannelRead(frame); } }
}
ByteBuf echoMsg = frame.content();
echoMsg.refCnt(); 获取引用计数
解决办法1:(新手不推荐,最好还是使用netty的自动释放逻辑,避免处理不当)
echoMsg.retain(); //手动进行引用计数加1,并在使用完成之后释放调
解决方法2:关闭SimpleChannelInboundHandler的自动释放(推荐)
package com.iflytek.iptv.websocket;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;public class PingPongHandler extends SimpleChannelInboundHandler<WebSocketFrame> {// 构造函数中设置autoRelease为falsepublic PingPongHandler() {super(false);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {if (frame instanceof PingWebSocketFrame) {// 接收到PING帧System.out.println("Received PING frame");// 发送PONG帧作为响应ctx.channel().writeAndFlush(new PongWebSocketFrame(Unpooled.buffer(0)));} else if (frame instanceof PongWebSocketFrame) {// 接收到PONG帧System.out.println("Received PONG frame");} else {// 其他类型的帧,继续传递给下一个处理器ctx.fireChannelRead(frame);}}
}
解决方法3:继承ChannelInboundHandlerAdapter ,默认不释放(推荐)
package com.iflytek.iptv.websocket;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class PingPongHandler extends ChannelInboundHandlerAdapter {private static final Logger log = LoggerFactory.getLogger(PingPongHandler1.class);@Overridepublic void channelRead(ChannelHandlerContext ctx, Object frame) throws Exception {if (frame instanceof PingWebSocketFrame) {// 接收到PING帧log.info("Received ping frame, connection is alive");// 发送PONG帧作为响应
// ctx.channel().writeAndFlush(new PongWebSocketFrame(Unpooled.buffer(0)));} else if (frame instanceof PongWebSocketFrame) {// 接收到PONG帧log.info("Received pong frame, connection is alive");} else {// 其他类型的帧,继续传递给下一个处理ctx.fireChannelRead(frame);}}
}
问题分析:
在Netty中,ByteBuf 是一个字节容器,它支持多种数据读写操作,并且其内部使用引用计数(refCnt)来管理资源的生命周期。引用计数用于确保资源(如内存)在不再需要时能够被适当释放,防止内存泄漏。
当你提到继承 SimpleChannelInboundHandler<WebSocketFrame> 和 ChannelInboundHandlerAdapter 并使用 ctx.fireChannelRead(frame) 时,ByteBuf 的引用计数表现不同,这主要是由于 SimpleChannelInboundHandler 和 ChannelInboundHandlerAdapter 处理 ByteBuf 的方式有所区别。
SimpleChannelInboundHandler
SimpleChannelInboundHandler<T> 是一个方便的类,它专门为处理特定类型的入站消息而设计。它会在消息传递到下一个 ChannelHandler 之前自动释放(release())传入的消息对象(如果消息实现了 ReferenceCounted 接口,如 ByteBuf)。这是因为它假设在 channelRead0(ChannelHandlerContext ctx, T msg) 方法中处理完消息后,当前处理器不需要再保留对该消息的引用。
因此,当你在 SimpleChannelInboundHandler 的 channelRead0 方法中调用 ctx.fireChannelRead(frame)(这里的 frame 是 WebSocketFrame 的一个实例,而 WebSocketFrame 内部通常包含 ByteBuf),由于 SimpleChannelInboundHandler 的设计,Netty 会在将消息传递给下一个处理器之前自动调用 release()。这就是为什么你看到引用计数减少的原因。
ChannelInboundHandlerAdapter
相反,ChannelInboundHandlerAdapter 是一个更通用的基类,它不假设你会在方法执行后立即释放消息。因此,当你在 ChannelInboundHandlerAdapter 的 channelRead 方法中调用 ctx.fireChannelRead(frame) 时,Netty 不会自动调用 release()。这意呀着你需要自己管理 ByteBuf 的生命周期,确保在不再需要时调用 release(),否则可能导致内存泄漏。
应该选择哪个?
- 如果你处理的是实现了
ReferenceCounted接口的对象(如ByteBuf),并且你的处理器在处理完消息后不再需要它,那么SimpleChannelInboundHandler是一个不错的选择,因为它可以自动管理引用计数。 - 如果你需要更细粒度的控制,比如你计划在多个处理器之间共享
ByteBuf,或者你的处理器只是将消息传递给下一个处理器而不立即处理它,那么ChannelInboundHandlerAdapter可能是更好的选择。但是,你需要确保自己正确地管理引用计数,避免内存泄漏。
结论
不是所有的中间处理器都必须继承 ChannelInboundHandlerAdapter。如果你处理的消息类型是特定的,并且你可以接受 SimpleChannelInboundHandler 的自动释放行为,那么使用它可能更方便。然而,如果你需要更复杂的处理逻辑或消息共享,那么 ChannelInboundHandlerAdapter 将提供更多的灵活性。重要的是要根据你的具体需求来选择适当的处理器类。
相关文章:
netty4报错:io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
背景:netty执行链中有一串自定义的handler,目前我想要在中间再加上一个pingPonghandler来进行控制帧的处理,从而避免ng的读写超时(客户要求,与他们建立的通道一直连接,不进行断连,从而需要考虑n…...
2022年汽车软件行业产业细分及发展趋势分析
2022年汽车软件行业产业细分及发展趋势分析 连接 2022年汽车软件行业产业细分及发展趋势分析...
如何通过变更让 PostgreSQL 翻车
在开发应用程序和维护其后台数据库集群的过程中,我们经常会遇到实践与理论、开发环境与生产环境之间的差异。其中一个典型的例子就是变更数据库中的列类型。 对于在 PostgreSQL(及其他符合 SQL 标准的系统)中变更列类型的常规操作࿰…...
MySQL表涉及规范
MySQL表设计规范是为了确保数据库表结构的合理性、可读性和可维护性。以下是一些建议和规范: 1.使用InnoDB存储引擎:InnoDB存储引擎提供了事务支持、行级锁定和外键约束,有助于提高数据的完整性和性能。 2.表名和字段名命名规范:…...
服务器Ubuntu22.04系统 使用dcocker部署安装ollama和搭配open_webui使用
服务器Ubuntu22.04系统 使用dcocker部署安装ollama和搭配open_webui使用 一、ubuntu和docker基本环境配置 1.更新包列表: 打开终端,输入以下命令: sudo apt-get updatesudo apt upgrade更新时间较长,请耐心等待 2. 安装docke…...
代理模式Proxy
一、代理模式(Proxy) 1.代理模式的定义 代理模式给某一个对象提供一个代理对象,并由代理对象控制对真实对象的访问,起到对代理对象已有功能的增强 通俗的来讲代理模式就是我们生活中常见的中介。 2.作用 中介隔离作用&#x…...
C++ 设计模式——抽象工厂模式
抽象工厂模式 抽象工厂模式 抽象工厂模式主要组成部分代码实现抽象工厂模式模式的 UML 图抽象工厂模式 UML 图解析优点和缺点适用场景 抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它通常用于需要创建多个产品…...
《亿级流量系统架构设计与实战》第十一章 Timeline Feed服务
Timeline Feed服务 一、概述1、分类2、功能 二、设计原理1、拉模式与用户发件箱2、推模式与用户收件箱3、推拉模式结合 三、关键技术1、内容与用户收件箱的交互(推模式)2、推送拆分子任务3、收件箱模型设计 内容总结自《亿级流量系统架构设计与实战》 一…...
氙灯老化试验箱试验机
氙灯老化试验箱,采用6.5KW大功率的精密水冷式氙灯,曝晒面积达到了6500cm2 功能强大,测试结果可靠 ◆ 满足国内外所有氙灯测试标准要求。 ◆ 采用氙灯灯管及滤光器组件,保证试验数据的可比性和重现性。 ◆ 自动旋转式三层鼓型样板架…...
【Qt】常用控件QRadioButton
常用控件QRadioButton QRadioButton是单选按钮,可以在多个选项中选择一个。 作为QAbstractButton和QWidget的子类,其属性和用法,对于QRadioButton同样适用。 属性说明 checkable 是否能选中 checked 是否已经被选中. checkable 是 checked…...
Mysql 离线版下载安装-(详细版)
Mysql 离线版下载安装-(详细版) 文章目录 Mysql 离线版下载安装-(详细版)1.0 下载地址2.0 解压到本地2.0.1 配置环境变量2.0.2 新建mysql配置文件ini2.0.3使用管理员启动 cmd 3.0 初始化密码忘记了4.0 修改初始化密码5.0 使用可视化工具登录Mysql 1.0 下载地址 地址࿱…...
Spring Boot和OCR构建车牌识别系统
博客主页: 南来_北往 系列专栏:Spring Boot实战 OCR介绍 OCR(Optical Character Recognition)是光学字符识别技术的缩写,它能够将图像中的文本转换为机器可读和编辑的数字文本格式。这种技术广泛应用于数据输入、文档管理…...
Java-自定义注解中成员变量是Class<?>
在Java中,自定义注解可以包含各种类型的成员变量,包括 Class<?> 类型。这种类型的成员变量 通常用于表示某个类的类型信息。下面我将详细介绍如何定义一个包含 Class<?> 类型成员变量的 自定义注解,并给出一些示例代码。 1. 定义自定义注解 定义一个自定义…...
SX_UNIX套接字通信_15
UNIX套接字通信的优势: UNIX套接字通信常用于一个项目中的进程之间通信,UNIX提供了与网络套接字相似的特性,但是避免了网络延迟,提高了性能,但是它只能在同一台机器上使用,无法跨越网络的进程间通信 实例&…...
JS模块化总结 | CommonJS、ES6
BV13W42197jR 个人笔记 目录 JS模块化基础知识1. 概述1.1 什么是模块化1.2 为什么需要模块化? 2 模块化规范3 导入&导出4 CommonJS规范4.1 初步体验4.2 导出数据4.3 导入数据4.4 扩展理解4.5 浏览器端运行 5 ES6模块化规范5.1 初步体验5.2 Node中运行ES65.3 导出数据①分别…...
25考研计算机组成原理复习·3.5高速缓冲存储器
高速缓冲存储器Cache 工作原理:将某些主存块复制到Cache中,缓和CPU与主存之间的速度矛盾局部性原理 时间局部性:现在访问的地址,不久之后也很可能被再次访问空间局部性:现在访问的地址,其附近的地址也很可…...
餐厅管理系统
目录 一、 系统简介 1.1需求分析 1.2 编程环境与工具 二、 系统总体设计 2.1 系统的功能模块图。 2.2 各功能模块简介。 三、 主要业务流程 (1)用户及管理员登录流程图 (2)信息添加流程 (3…...
杭州百腾教育科技 TiDB 6.5 to 7.5 升级记录
作者: reAsOn2010 原文来源: https://tidb.net/blog/612103f3 背景 使用 TiDB 作为我们的全量数据库已经有六七年了,当时还是 2.0 版本。早期TiDB的迭代和新特性的发布对于实际使用的影响还是很大的,所以从那个时候开始就有每…...
Redis的缓存穿透、击穿、雪崩
目录 缓存穿透 定义: 解决方法: 缓存击穿 定义: 解决方案: 缓存雪崩 定义: 解决方案: 缓存穿透、缓存击穿和缓存雪崩的区别 缓存穿透 定义: 查询一个不存在的数据,数据库未…...
【Django开发】前后端分离django美多商城项目第1篇:欢迎来到美多 项目主要页面介绍【附代码文档】
本教程的知识点为: 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计: 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
