美文网首页
记一次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泄露

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