美文网首页
记一次netty泄露

记一次netty泄露

作者: 靈08_1024 | 来源:发表于2019-04-24 15:12 被阅读0次

初次用netty来企业实战,遇到了netty泄露。

本次是用来测试某功能的QPS,但是在启动netty时,出现了如下文字:

四月 24, 2019 2:53:17 下午 io.netty.util.ResourceLeakDetector reportUntracedLeak 严重: LEAK: ByteBuf.release() was not called before it's garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option '-Dio.netty.leakDetection.level=advanced' or call ResourceLeakDetector.setLevel() See http://netty.io/wiki/reference-counted-objects.html for more information.

发现上面提到'-Dio.netty.leakDetection.level=advanced参数,加入到VM arguments中。而这个参数是netty对 1% buffer样本检测, 并且告知是在哪里访问泄漏的 buffer的。与之等效的是在netty启动的java文件时候加入ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);然后出现如下错误内容:

四月 24, 2019 2:54:33 下午 io.netty.util.ResourceLeakDetector reportTracedLeak
严重: LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 2
#2:
    io.netty.buffer.AdvancedLeakAwareByteBuf.toString(AdvancedLeakAwareByteBuf.java:741)
    controller.XXCodec.decode(XXCodec.java:32)
    io.netty.handler.codec.ByteToMessageCodec$1.decode(ByteToMessageCodec.java:42)
    io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
    io.netty.handler.codec.ByteToMessageCodec.channelRead(ByteToMessageCodec.java:103)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
    io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    java.lang.Thread.run(Thread.java:748)
#1:
    io.netty.buffer.AdvancedLeakAwareByteBuf.writeBytes(AdvancedLeakAwareByteBuf.java:603)
    io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:829)
    controller.XXCodec.decode(XXCodec.java:30)
    io.netty.handler.codec.ByteToMessageCodec$1.decode(ByteToMessageCodec.java:42)
    io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
    io.netty.handler.codec.ByteToMessageCodec.channelRead(ByteToMessageCodec.java:103)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
    io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    java.lang.Thread.run(Thread.java:748)
Created at:
    io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:271)
    io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:179)
    io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:115)
    io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:828)
    controller.XXCodec.decode(XXCodec.java:30)
    io.netty.handler.codec.ByteToMessageCodec$1.decode(ByteToMessageCodec.java:42)
    io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
    io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
    io.netty.handler.codec.ByteToMessageCodec.channelRead(ByteToMessageCodec.java:103)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
    io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
    io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
    io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
    io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
    io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
    io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
    io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
    io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    java.lang.Thread.run(Thread.java:748)

在最上面的#2的第二行,提到了我的文件,这是一个编解码文件,其中涉及的方法是:

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() >= 18) {
            String msg = in.readBytes(18).toString(Charset.forName("utf-8"));
            out.add(msg);
        }
    }

后来经查询,是自己的bytebuf要进行自己释放,netty对于bytebuf是采用引用计数法的,而只有在该变量引用数变为0时,才会释放掉。真是哭死。。
最后修改为:

@Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        ByteBuf byteBuf = in.readBytes(18);
        if (in.readableBytes() >= 18) {
            String msg = byteBuf.toString(Charset.forName("utf-8"));
            out.add(msg);
        }
        if(byteBuf.refCnt()>0)
            byteBuf.release();
    }

引用
https://emacsist.github.io/2018/04/28/翻译netty中的引用计数对象/

相关文章

  • 记一次netty泄露

    初次用netty来企业实战,遇到了netty泄露。 本次是用来测试某功能的QPS,但是在启动netty时,出现了如...

  • 2018-10-28

    阿里云Elasticsearch 智能化运维实践 lubuntu Netty堆外内存泄露排查盛宴 In A Par...

  • 记一次内存泄露优化

    前言 dialog引起的内存泄露 最近在优化项目发现好几个地方出现了内存泄露 我封装了一个TipDialog,用在...

  • 记一次内存泄露调试

    首先介绍一下相关背景。最近在测试一个程序时发现,在任务执行完成之后,从任务管理器上来看,内存并没有下降到理论值上。...

  • JVM问题排查实战系列

    JVM问题排查实战 记一次频繁FGC的简单排查 一次JVM GC长暂停的排查过程 如何使用MAT进行内存泄露分析

  • 记一次Fragment的内存泄露

    最近遇到一个内存泄露, 代码非常简单 : 先打开一个 FragmentA, 然后通过 replace 替换成 Fr...

  • k8s中,写日志引起pod cache增加问题

    记一次k8s中内存泄露的问题监控抓取的地址为cadvisor的地址,取的pod的mem分为rss、cached、u...

  • netty 堆外内存泄露排查盛宴

    这篇文章对于排查使用了 netty 引发的堆外内存泄露问题排查,有一定的通用性,希望对你有所启发 背景 最近在做一...

  • 【Tips】 拒绝循环引用

    前言 最近项目中检查是否有内存泄露,发现大部分的情况都是由于block的循环引用而导致的内存泄露,所以借此机会来记...

  • Netty 源码解析(五): Netty 的线程池分析

    Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty 源码...

网友评论

      本文标题:记一次netty泄露

      本文链接:https://www.haomeiwen.com/subject/xzdggqtx.html