• Netty ByteBuf泄露定位修改。


    1. ByteBuf

    2. 问题描述

    日志记录中报堆外内存溢出。

    3. 问题定位及修改

    Netty提供了ByteBuf泄露的检测机制。

    JVM启动参数中添加: -Dio.netty.leakDetectionLevel=advanced , log4j2.xml配置io.netty日志记录即可。

    禁用(DISABLED) – 完全禁止泄露检测,省点消耗。
    简单(SIMPLE)   – 默认等级,告诉我们取样的1%的ByteBuf是否发生了泄露,但总共一次只打印一次,看不到就没有了。
    高级(ADVANCED) – 告诉我们取样的1%的ByteBuf发生泄露的地方。每种类型的泄漏(创建的地方与访问路径一致)只打印一次。对性能有影响。
    偏执(PARANOID) – 跟高级选项类似,但此选项检测所有ByteBuf,而不仅仅是取样的那1%。对性能有绝大的影响。

    检测到如下泄露点,

    举例1

     13:29:25.273 [MODBUS_MESSAGE_POOL-thread-14] [] [] [] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
    Created at:
        io.netty.buffer.AdvancedLeakAwareByteBuf.writeBytes(AdvancedLeakAwareByteBuf.java:604)
        io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:849)
        com.pinnet.protocol.hwmodbus.message.ModbusMessageRunnable.run(ModbusMessageRunnable.java:46)
        java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        java.lang.Thread.run(Thread.java:748)
    

     可以看到readBytes()创建后,没有释放。

    修改:

    buffer.readBytes(4).release();

    举例2:

    2018-06-30 13:29:25.278 [MESSAGE_POOL-thread-14] [] [] [] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
        #1:
        io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:273)
        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.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
        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.handler.ssl.SslHandler.unwrap(SslHandler.java:1380)
        io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1159)
        io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1194)
        io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
        #2:
        io.netty.buffer.AdvancedLeakAwareByteBuf.getUnsignedShort(AdvancedLeakAwareByteBuf.java:172)
        io.netty.handler.codec.LengthFieldBasedFrameDecoder.getUnadjustedFrameLength(LengthFieldBasedFrameDecoder.java:469)
        io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:417)
        com.pinnet.protocol.hwmodbus.tcp.MobusLengthDecoder.decode(MobusLengthDecoder.java:32)
        #3:
        io.netty.buffer.AdvancedLeakAwareByteBuf.order(AdvancedLeakAwareByteBuf.java:70)
        io.netty.handler.codec.LengthFieldBasedFrameDecoder.getUnadjustedFrameLength(LengthFieldBasedFrameDecoder.java:462)
        io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:417)
        com.pinnet.protocol.hwmodbus.tcp.MobusLengthDecoder.decode(MobusLengthDecoder.java:32)
        io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:343)
        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)
    #4:
            Hint: 'decoder' will handle the message from this point.
    #5:
            Hint: 'idleHandler' will handle the message from this point.

     修改:解码器中释放Bytebuf in

    public class MobusLengthDecoder extends LengthFieldBasedFrameDecoder {
    
        public MobusLengthDecoder(ByteOrder byteOrder, int maxFrameLength,
                int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
                int initialBytesToStrip, boolean failFast) {
            super(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength,
                    lengthAdjustment, initialBytesToStrip, failFast);
        }
    
        @Override
        protected Object decode(ChannelHandlerContext ctx,
                io.netty.buffer.ByteBuf in) throws Exception {
    
            ByteBuf buf = (ByteBuf) super.decode(ctx, in);
            // LEAK: ByteBuf.release() was not called before it's garbage-collected.
            in.release();
    
            ...
        }
    
    }
  • 相关阅读:
    线程带参数操作
    静态页面不识别include
    当网站遭遇DDOS攻击的解决方案及展望
    带进度条上传控件
    用js实现了表格数据管理的以下几个功能:
    怎么面试一个人
    map的使用
    在Axapta中实现trim函数
    Axapta财务过账分析(一)
    在Axapta中实现split函数
  • 原文地址:https://www.cnblogs.com/eaglediao/p/7004404.html
Copyright © 2020-2023  润新知