栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

记一次 netty 堆外内存泄漏排查

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

记一次 netty 堆外内存泄漏排查

netty内存泄漏: 问题描述

测试环境netty服务日志提示有内存泄漏:

使用netty开发的聊天服务,运行一段时间后日志会显示

2022-06-17 10:35:53.488 ERROR 27253 --- [tLoopGroup-13-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.newDirectBuffer(PooledByteBufAllocator.java:331)
        io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:185)
        io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:176)
        io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:113)
        io.netty.buffer.ByteBufUtil.readBytes(ByteBufUtil.java:430)
        io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.decode(WebSocket08FrameDecoder.java:304)
        io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
        io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
        io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
        io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
        io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
        io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
        io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
        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)
异常分析:
  • netty消息的读写使用的是ByteBuf,默认的实现是池化的直接内存,即PooledByteBuf。
  • PooledByteBuf的回收机制是使用的引用计数法,从 Netty 版本 4 开始,某些对象的生命周期由它们的引用计数管理,因此一旦不再使用(引用计数变成0),Netty 就可以将它们(或它们的共享资源)返回到对象池(或对象分配器)。
  • 引用计数的缺点是很容易泄漏引用计数的对象。因为 JVM 不知道 Netty 实现的引用计数,所以一旦JVM认为它们变得无法访问,即使它们的引用计数不为零,JVM也会自动对它们进行垃圾收集。这样就不会触发PooledByteBuf的回收机制。一个对象一旦被垃圾回收就不能复活,因此不能返回到它来自的池中,从而会产生内存泄漏。

简单来说,就是程序中的某个对象的引用计数出了问题,对象被垃圾回收器回收的时候,引用计数不为0,导致其占用的直接内存未被释放,从而会产生内存泄漏。


更改日志级别:

这个错误日志是由netty的内存泄漏检测机制提示的,Netty的内存泄漏检测分为四个级别:

  • DISABLED - 完成禁止检测内存泄漏,这个是不推荐。
  • SIMPLE - 如果buffer中出现1%的内存泄漏,打印错误日志,就是上面那样。但是日志 是看不到详细在什么位置出现了内存泄漏。鉴于性能考虑,这个是在生产环境中默认使用。
  • ADVANCED - 如果buffer的1%出现内存泄漏,打印错误,并且输出详细的内存泄漏信息。
  • PARANOID - 这个和ADVANCED输出的内容是一样的,但它会对每一次请求的buffer做检查。很适用于调试和单元测试。

在代码中更改日志级别或者在启动参数中指定日志级别

## 程序中
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID);
## 或者java 启动命令中增加参数
-D io.netty.leakDetectionLevel=PARANOID

定位问题:

更改日志级别后,会在日志中打印更详细的信息,我们代码中有一段

//      处理 IllegalReferenceCountException 异常 .
        ByteBuf echoMsg = msg.content();
        echoMsg.retain();

之前的业务逻辑中,为了处理一个IllegalReferenceCountException,手工给引用计数+1了,后续代码变更,没有去掉这个逻辑,导致内存泄漏

结论:

去掉就好了,哈哈

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/978193.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号