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

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

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

相关文章

JAVA将集合切分成指定份数(简易)

JAVA将集合切分成指定份数 主要方法 /** * 主要方法* param list 切分的集合* param count 切成的份数* return*/ public static List<List> splitList(List list,int count){if(count <0 ){return Lists.newArrayList();}List<List> result Lists.newArrayL…

ECharts关系图-关系图11,附视频讲解与代码下载

引言&#xff1a; 关系图&#xff08;或称网络图、关系网络图&#xff09;在数据可视化中扮演着至关重要的角色。它们通过节点&#xff08;代表实体&#xff0c;如人、物体、概念等&#xff09;和边&#xff08;代表实体之间的关系或连接&#xff09;的形式&#xff0c;直观地…

java 对mongodb操作封装工具类

在 Java 中&#xff0c;封装 MongoDB 操作的工具类是非常常见的做法。使用 MongoDB 官方的 Java 驱动程序&#xff0c;结合常用的工具类封装&#xff0c;可以使得与 MongoDB 的交互更加方便和清晰。下面是一个简单的 MongoDB 操作封装工具类的示例代码。 前提 首先&#xff0…

事件响应基本流程

虽然安全专业人员努力保护系统免受恶意攻击或人为疏忽&#xff0c;但尽管做出了这些努力&#xff0c;但不可避免地会出现问题。出于这个原因&#xff0c;安全专业人员也扮演着第一响应者的角色。要了解事件响应&#xff0c;首先要了解用于描述各种网络攻击的术语。 违规 失控…

OpenHarmony的分布式服务框架介绍与实现解析

OpenHarmony的分布式服务框架是一个用于实现设备间高效协作与资源共享的重要架构&#xff0c;以下是其详细介绍&#xff1a; 框架概述 OpenHarmony的分布式服务框架基于分布式软总线、分布式数据管理、分布式Profile等技术特性&#xff0c;构建了统一的分布式服务管理机制&am…

Java爬虫获取1688关键字接口详细解析

概述 在电商领域&#xff0c;获取商品信息和价格对于市场分析、价格监控和供应链管理至关重要。1688作为中国领先的B2B电商平台&#xff0c;提供了海量的商品数据。本文将详细介绍如何利用Java爬虫技术合法合规地获取1688商品关键字接口数据。 前期准备 Java开发环境&#x…

【漏洞复现】BIG-IP Next Central Manager OData 注入漏洞(CVE-2024-21793)

🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦 一、漏洞概述 1.1漏洞简介 漏洞名称:BIG-IP Next Central Manager OData 注入漏洞漏洞编号:CVE-2024-21793漏洞威胁等级:超危影响范围:BIG-IP Next Central Manage…

vscode 识别git目录

vscode 偶尔无法识别使用git 新托管的项目。 以下是我提供的解决方案——重启 git.enabled VS Code配置问题&#xff1a; 有时候&#xff0c;VS Code的配置可能会导致无法识别.git文件夹。确保你的VS Code配置中启用了Git的相关功能。你可以通过”Settings”&#xff08;设置…

网安瞭望台第17期:Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析

国内外要闻 Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析 在网络安全的复杂战场中&#xff0c;近期出现了一个值得关注的动态&#xff1a;名为 Rockstar 2FA 的钓鱼即服务&#xff08;PhaaS&#xff09;工具包遭遇变故&#xff0c;意外推动了另一个新生服务 Flo…

抚琴成一快-如何即兴谱例

如何即兴配套谱例 1.即兴01谱例2.即兴02谱例 1.即兴01谱例 2.即兴02谱例 慢推弦&#xff0c;1.5比较合适

希腊字母表

希腊字母 以下是数学和科学中常用的 希腊字母 及其用途的对照表&#xff0c;包括大写和小写形式&#xff1a; 序号字母名称发音&#xff08;英文&#xff09;数学与科学用途1ΑαAlphaˈlfə表示角度、系数、角速度等2ΒβBetaˈbeɪtə 或 ˈbiːtə表示系数、β辐射、概率密…

3090. 每个字符最多出现两次的最长子字符串

题目内容&#xff1a; 给你一个字符串 s &#xff0c;请找出满足每个字符最多出现两次的最长子字符串&#xff0c;并返回该 子字符串 的 最大 长度。 示例 1&#xff1a; 输入&#xff1a; s "bcbbbcba" 输出&#xff1a; 4 解释&#xff1a; 以下子字符串长…

uniapp登录

第一步整登录 先整个appid APPID和APPSecret https://developers.weixin.qq.com/community/develop/article/doc/000ca4601b8f70e379febac985b413 一个账号只能整一个小程序 正确流程 调用uni.login https://juejin.cn/post/7126553599445827621 https://www.jb51.net/a…

[python]pymc3-3.11.0安装后测试代码

测试通过环境&#xff1a; pymc33.11.0 python3.8 测试代码&#xff1a; import arviz as az import matplotlib.pyplot as plt import numpy as np import pymc3 as pm RANDOM_SEED 8927 np.random.seed(RANDOM_SEED) az.style.use("arviz-darkgrid") # True p…

基于微信小程序的短视频系统(SpringBoot)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

深入理解 Linux wc 命令

文章目录 深入理解 Linux wc 命令1. 基本功能2. 常用选项3. 示例3.1 统计文件的行、单词和字符数3.2 仅统计行数3.3 统计多个文件的总和3.4 使用管道统计命令输出的行数 4. 实用案例4.1 日志分析4.2 快速统计代码行数4.3 统计单词频率 5. 注意事项6. 总结 深入理解 Linux wc 命…

HarmonyOs:创建线程的3种方式

使用Worker创建线程 基本概念&#xff1a;Worker主要为应用程序提供多线程运行环境&#xff0c;可让应用程序在执行过程中与宿主线程分离&#xff0c;在后台线程中运行脚本进行耗时操作&#xff0c;避免计算密集型或高延迟任务阻塞宿主线程。使用方法&#xff1a; 创建Worker线…

DataV的安装与使用(Vue3版本)

1、DataV(vue3)地址&#xff1a;DataV Vue3TSVite版 | DataV - Vue3 2、使用 npm install kjgl77/datav-vue3 安装 3、全局引入。 4、此时就可以按需使用了~

云原生服务网格Istio实战

基础介绍 1、Istio的定义 Istio 是一个开源服务网格&#xff0c;它透明地分层到现有的分布式应用程序上。 Istio 强大的特性提供了一种统一和更有效的方式来保护、连接和监视服务。 Istio 是实现负载平衡、服务到服务身份验证和监视的路径——只需要很少或不需要更改服务代码…

Flutter web - 5 项目打包优化

介绍 目前 flutter 对 web 的打包产物优化较少&#xff0c;存在 main.dart.js 单个文件体积过大问题&#xff0c;打包文件名没有 hash 值&#xff0c;如果有使用 CDN 会存在资源不能及时更新问题。本文章会对这些问题进行优化。 优化打包产物体积 从打包产物中可以看到其中 …