Netty内存泄漏:LEAK: ByteBuf.release() was not called before it‘s garbage-collected.

文章目录

  • 前言
  • ByteBuf
  • 问题分析
  • 解决方法
    • 单个方法中
    • ChannelHandler链中


前言

项目中使用Netty接收设备传递的数据时,查看日志发现有时会报错:LEAK: ByteBuf.release() was not called before it's garbage-collected.
根据提示也可以看出是使用ByteBuf时,没有及时调用ByteBuf.release() 而引发的内存泄漏。

以下为日志中的报错信息:

2024-12-18 18:18:05.694 ERROR 841 --- [ntLoopGroup-5-1] io.netty.util.ResourceLeakDetector       : LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
	io.netty.buffer.PooledByteBufAllocator.newHeapBuffer(PooledByteBufAllocator.java:332)
	io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:168)
	io.netty.buffer.AbstractByteBufAllocator.heapBuffer(AbstractByteBufAllocator.java:159)
	com.lc.netty.ListenChannelInitHandler.initChannel(ListenChannelInitHandler.java:141)
	com.lc.netty.ListenChannelInitHandler.initChannel(ListenChannelInitHandler.java:26)
	io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:129)
	io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:112)
	io.netty.channel.AbstractChannelHandlerContext.callHandlerAdded(AbstractChannelHandlerContext.java:964)
	io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:610)
	io.netty.channel.DefaultChannelPipeline.access$100(DefaultChannelPipeline.java:46)
	io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1474)
	io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1126)
	io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:651)
	io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:503)
	io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:416)
	io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:475)
	io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
	io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:416)
	io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:515)
	io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
	io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	java.lang.Thread.run(Thread.java:748)

ByteBuf

Netty中ByteBuf按是否使用了池化技术,ByteBuf分为两类,

  • 一类是非池化的ByteBuf,包括UnpooledHeapByteBuf、UnpooledDirectByteBuf等等,每次I/O读写都会创建一个新ByteBuf,频繁进行大块内存的分配和回收对性能有一定影响,非池化的ByteBuf可以通过JVM GC自动回收,也推荐手动回收UnpooledDirectByteBuf等使用堆外内存的ByteBuf;
  • 另一类是池化的ByteBuf,包括pooledHeapByteBuf、pooledDirectByteBuf等等,其先申请一块大内存池,在内存池中分配空间,对于这种应用级别的内存二次分配,就需要手动对池化的ByteBuf进行释放,否则就有可能出现内存泄露的问题。

问题分析

出现这个问题是因为程序中使用了池化的ByteBuf(PooledByteBuf)。而PooledByteBuf的内存空间是从内存池中分配的,PooledByteBuf通过引用计数来管理内存。当创建一个池化的ByteBuf时,其引用计数初始化为 1。每次将ByteBuf传递给其他对象或在某个地方被引用时,引用计数应该相应增加(通常在 Netty 内部机制中自动处理)。
当不再需要这个ByteBuf时,应该调用release()方法来减少引用计数(每次调用release()-1)。,减小到0时就会将内存归还在内存池中。
如果没有调用release(),引用计数不会减少到 0,那么内存将不会被释放回内存池,即使应用程序不再使用这个ByteBuf,它所占用的内存仍然被保留,从而导致内存泄漏。

解决方法

单个方法中

既然通过日志已经知道了内存泄漏的位置,接下来就需要再使用完手动调用其release方法释放

ByteBuf buffer = Unpooled.copiedBuffer("test".getBytes());
try {
    
    ...
} catch (Exception e) {
    buffer.release();
    log.error("数据异常:", e);
}finally {
    buffer.release();
}

ChannelHandler链中

因为 pipeline 的存在,一般需要将 ByteBuf 传递给下一个 ChannelHandler,如果在 finally 中 release 了,就失去了传递性。
所以规则变成了 谁是最后使用者,谁负责释放。另外,更要注意的是各种 异常情况,ByteBuf没有成功传递到下一个Hanlder,还在自己地界里的话,一定要进行释放。

  • 入站 ByteBuf 处理原则
    • 对原始 ByteBuf 不做处理,调用 ctx.fireChannelRead(msg) 向后传递,这时无须 release
    • 将原始 ByteBuf 转换为其它类型的 Java 对象,这时 ByteBuf 就没用了,必须 release
    • 如果不调用 ctx.fireChannelRead(msg) 向后传递,那么也必须 release
    • 注意各种异常,如果 ByteBuf 没有成功传递到下一个 ChannelHandler,必须 release
    • 假设消息一直向后传,那么 TailContext 会负责释放未处理消息(原始的 ByteBuf)
  • 出站 ByteBuf 处理原则
    • 出站消息最终都会转为 ByteBuf 输出,一直向前传,由 HeadContext flush 后 release
  • 异常处理原则
    • 有时候不清楚 ByteBuf 被引用了多少次,但又必须彻底释放,可以循环调用 release 直到返回 true

相关文章:
Netty-组件ByteBuf

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

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

相关文章

MySQL的分析查询语句

【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客 《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…

【递归,搜索与回溯算法 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)

优美的排列 题目解析 算法原理 解法 :暴搜 决策树 红色剪枝:用于剪去该节点的值在对应分支中,已经被使用的情况,可以定义一个 check[ ] 紫色剪枝:perm[i] 不能够被 i 整除,i 不能够被 per…

观察者模式(sigslot in C++)

大家,我是东风,今天抽点时间整理一下我很久前关注的一个不错的库,可以支持我们在使用标准C的时候使用信号槽机制进行观察者模式设计,sigslot 官网: http://sigslot.sourceforge.net/ 本文较为详尽探讨了一种观察者模…

GitCode 光引计划投稿|智能制造一体化低代码平台 Skyeye云

随着智能制造行业的快速发展,企业对全面、高效的管理解决方案的需求日益迫切。然而,传统的开发模式往往依赖于特定的硬件平台,且开发过程繁琐、成本高。为了打破这一瓶颈,Skyeye云应运而生,它采用先进的低代码开发模式…

高校就业管理:系统设计与实现的全流程分析

3.1可行性分析 在项目进行开发之前,必须要有可行性分析报告,分别从技术角度,经济角度,操作角度上面进行分析,经过可行性分析是实现科学开发的必要步骤。 3.1.1技术可行性 从技术的角度出发,目前采用开发的技…

超级AI图像放大工具Upscayl:让你的照片细节更清晰,色彩更鲜艳!

前言 Hello大家好,我又来推荐非常好用的AI图片无损放大器,模糊图片秒变高清,Upscayl是一个免费开源的AI图像超分辨率工具。它使用AI模型来通过猜测细节的方式增强图像并提高其分辨率。该工具适用于Linux、macOS和Windows操作系统 安装环境 [名称]&…

1.gitlab 服务器搭建流程

前提条件: 一、服务器硬件水平 搭建gitlab服务器最低配置要求2核4G,低于这个配置的服务器运行效果很差。 gitlab官网:https://about.gitlab.com/ 下载地址:gitlab/gitlab-ce - Packages packages.gitlab.com 本机ubuntu 二、安装依赖 su…

Ai编程从零开始全栈开发一个后台管理系统之用户登录、权限控制、用户管理-前端部分(十二)

云风网 云风笔记 云风知识库 一、创建前端部分 1、vite初始化项目 npm create vitelatest admin-frontend – --template vue-ts 2、安装必要的依赖 npm install vue-router pinia axios element-plus element-plus/icons-vue安装完成后package.json如下: {&qu…

CVE-2024-34351 漏洞复现

CVE-2024-34351&#xff0c;由Next.js异步函数createRedirectRenderResult导致的SSRF。 影响版本&#xff1a;13.4.0< Next.js < 14.1.1 参考文章&#xff1a; Next.js Server-Side Request Forgery in Server Actions CVE-2024-34351 GitHub Advisory Database Gi…

怎么理解GKE Role-Based Access Control (RBAC) 和 Pod Security Policies (PSP)

怎么理解GKE Role-Based Access Control (RBAC) 和 Pod Security Policies (PSP) 理解 Google Kubernetes Engine (GKE) 中的角色基于访问控制&#xff08;RBAC&#xff09;和 Pod 安全策略&#xff08;PSP&#xff09;对于确保集群安全性至关重要。以下是对这两个概念的详细解…

什么是 DevOps 自动化?

DevOps 自动化是一种现代软件开发方法&#xff0c;它使用工具和流程来自动化任务并简化工作流程。它将开发人员、IT 运营和安全团队聚集在一起&#xff0c;帮助他们有效协作并交付可靠的软件。借助 DevOps 自动化&#xff0c;组织能够处理重复性任务、优化流程并更快地将应用程…

帝国CMS:如何去掉帝国CMS登录界面的认证码登录

如果在安装的时候&#xff0c;不小心选中了认证码选项&#xff0c;那么后面登录帝国后台都会要求输入认证码才能登录&#xff0c;如何去除这个设置呢&#xff0c;笔者以古诗词网 www.gushichi.com为例&#xff0c;为大家举例说明&#xff01; 去除步骤如下&#xff1a; 1.前往…

4.2V单节锂电池充电电路(TP4056)、USB与锂电池切换电路分享

一、充电原理图 1、连接说明 BAT_VCC和BAT_GND连接电池 VUSB和GND连接USB电源 2、芯片介绍 a、DW01 DW01芯片是一种电池管理保护芯片&#xff0c;主要用于锂离子电池的保护和管理。DW01芯片具有以下特点&#xff1a; 电池电压保护&#xff1a;DW01芯片可以监测和保护电池的…

ChatGPT生成接口文档实践案例(二)

不难发现&#xff0c;两个方案都出色地完成了接口文档的生成&#xff0c;但笔者更喜欢Response 2的表达&#xff0c;因为其描述更加全面。 还可以让ChatGPT生成符合OpenAPI 3.0规范的接口文档&#xff0c;以便于项目相关成员阅读&#xff0c;如图5-13所示。 为什么要生成OpenAP…

MFC用List Control 和Picture控件实现界面切换效果

添加List Control 和Picture控件 添加 3个子窗体 把子窗体边框设置为None, 样式设为Child 声明 CListCtrl m_listPageForm;void ShowForm(int nIndex);void CreatFormList();void CMFCApplication3Dlg::DoDataExchange(CDataExchange* pDX) {CDialogEx::DoDataExchange(pDX);DD…

JavaWeb Servlet的反射优化、Dispatcher优化、视图(重定向)优化、方法参数值获取优化

目录 1. 背景2. 实现2.1 pom.xml2.2 FruitController.java2.3 DispatcherServlet.java2.4 applicationContext.xml 3. 测试 1. 背景 前面我们做了Servlet的一个案例。但是存在很多问题&#xff0c;现在我们要做优化&#xff0c;优化的步骤如下&#xff1a; 每个Fruit请求都需…

frp内网穿透云服务器。云服务器映射多个家庭局域网内网端口。家庭Windows主机内网运行多个web程序

这篇文章最终要实现的效果是&#xff0c;把云服务器的公网IP绑定到自己本地局域网上的主机一样的效果。相当于局域网主机有了一个自己的公网IP地址。 FRP (Fast Reverse Proxy) 是一个用 Go 语言编写的高性能反向代理应用程序&#xff0c;主要用于内网穿透。它允许位于 NAT 或…

windos 安装docker

文章目录 安装1.下载安装包2.双击安装软件 验证修改国内镜像地址FAQDocker Engine stopped 小结 安装 1.下载安装包 到官网下载适配的安装包&#xff1a;https://www.docker.com/products/docker-desktop/ 2.双击安装软件 选择ok 等待安装依赖 安装完成以后会重启电脑&am…

【已解决】黑马点评项目Redis版本替换过程中误删数据库后前端显示出现的问题

为了实现基于Redis的Stream结构作为消息队列&#xff0c;实现异步秒杀下单的功能&#xff0c;换Redis版本 Redis版本太旧了&#xff0c;所以从3.2.1换成了5.0.14 此时犯了一个大忌&#xff0c;因为新的Redis打开后&#xff0c;没有缓存&#xff0c;不知道出了什么问题&#xf…

Odoo 免费开源 ERP:通过 JavaScript 创建对话框窗口的技术实践分享

作者 | 老杨 出品 | 上海开源智造软件有限公司&#xff08;OSCG&#xff09; 概述 在本文中&#xff0c;我们将深入研讨如何于 Odoo 18 中构建 JavaScript&#xff08;JS&#xff09;对话框或弹出窗口。对话框乃是展现重要讯息、确认用户操作以及警示用户留意警告或错误的行…