美文网首页
netty 解码小坑

netty 解码小坑

作者: 杭州_mina | 来源:发表于2018-07-18 12:55 被阅读0次

    1. in.readBytes 导致堆外内存泄漏

    使用netty 中偶现 LEAK: ByteBuf.release() was not called before it's garbage-collected. 在几次检查自己的代码,发现ByteBuf都有释放。就是找不到问题,翻阅了一下netty的官方文档,有两种方式可以 打印出泄漏的详细信息

    1. ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
    2. -Dio.netty.leakDetectionLevel=advanced
      打印日志如下:
        io.netty.buffer.AdvancedLeakAwareByteBuf.writeBytes(AdvancedLeakAwareByteBuf.java:600)
        io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:829)
        com.XXX.XXX.XXX.network.codec.XXXTcpDecoder.decode(XXXTcpDecoder.java:55)
        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:362)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
        io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
        io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
        io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
        io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
        io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
        io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
        java.lang.Thread.run(Thread.java:748)
    Created at:
        io.netty.util.ResourceLeakDetector.track(ResourceLeakDetector.java:237)
        io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:331)
        io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:181)
        io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:117)
        io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:828)
        com.XXX.XXX.XXX.network.codec.XXXTcpDecoder.decode(XXXTcpDecoder.java:55)
        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:362)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
        io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
        io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
        io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
        io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
        io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
        io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
        java.lang.Thread.run(Thread.java:748)
    

    com.XXX.XXX.XXX.network.codec.XXXTcpDecoder.decode(XXXTcpDecoder.java:55
    来看一下这一行明确提示泄漏的地方,然后看了一下对应的代码一脸懵逼


    image.png

    in.readBytes 需要释放bytebuf ???? 这他妈什么操作 吓得我赶紧看了一下源代码。。 注意 我特么也很sb 仔细看入参 一个是 long 一个是 byte[] 导致我浪费了很多时间

      @Override
        public ByteBuf readBytes(byte[] dst) {
            readBytes(dst, 0, dst.length);
            return this;
        }
    

    没毛病啊,非常奇怪。为啥!!!!! 然后就是各种google
    加了 ReferenceCountUtil.release(in);

        in.readByte();
        int dataLength = remaining - 17;
        byte[] dataByte = new byte[dataLength];
        in.readBytes(dataByte);
        String data = new String(dataByte);
        in.readBytes(8);
        。。。。。
        ReferenceCountUtil.release(in);
    
    

    不但没用,链接都报错了!!!!!
    接着开始怀疑这个是不是netty自身的bug。。。
    换了版本还是有问题!!!!! 受不了!!!!!
    然后继续思考人生。无意再次点击看源码。。突然有一句mmp 不知当讲不当讲!!!

     @Override
        public ByteBuf readBytes(int length) {
            checkReadableBytes(length);
            if (length == 0) {
                return Unpooled.EMPTY_BUFFER;
            }
    
            ByteBuf buf = alloc().buffer(length, maxCapacity);
            buf.writeBytes(this, readerIndex, length);
            readerIndex += length;
            return buf;
        }
    

    .... readBytes方法返回新的byteBuf ???


    image.png

    那特么我刚开始看是哪个源码??? 然后把整个 AbstractByteBuf 看了一遍
    内心崩溃 readBytes 方法有很多,每个入参不同,但是!!!!!!
    readBytes(int length) 这个是返回一个新的bytebuf 所以需要释放掉!!!
    弄了半天,还是自己sb。从错误中已经明确提示哪一行没有释放,但是结果还是饶了这么多弯。。。。。。

    相关文章

      网友评论

          本文标题:netty 解码小坑

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