zoukankan      html  css  js  c++  java
  • [netty4][netty-common]netty之ResourceLeakDetector的使用与实现

    netty之ResourceLeakDetector的使用与实现

    通过WeakReference和ReferenceQueue做针对需要手动释放的资源的侦测

    使用

    1. 设置日志级别:
    ServerBootstrap b =new ServerBootstrap();
    b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
    .option(ChannelOption.SO_BACKLOG, 2048)
    .handler(new LoggingHandler(LogLevel.DEBUG))
    .childHandler(new ChildChannelHandler());
    
    2017-01-19 10:04:49  [ nioEventLoopGroup-1-0:1628830 ] - [ ERROR ]  LEAK: ByteBuf.release() was not called before it's garbage-coll...
    
    1. ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);或者通过JVM参数配置
      日志:
    2017-01-19 10:35:59  [ nioEventLoopGroup-1-0:665092 ] - [ ERROR ]  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: 5
    #5:
        io.netty.buffer.AdvancedLeakAwareByteBuf.readBytes(AdvancedLeakAwareByteBuf.java:435)
    

    分析

    [ ERROR ] LEAK:

    // ResourceLeakDetector
    protected void reportTracedLeak(String resourceType, String records) {
        logger.error(
                "LEAK: {}.release() was not called before it's garbage-collected. " +
                "See http://netty.io/wiki/reference-counted-objects.html for more information.{}",
                resourceType, records);
    }
    
    private void reportLeak() {
        if (!logger.isErrorEnabled()) {
            clearRefQueue();
            return;
        }
    
        // Detect and report previous leaks.
        for (;;) {
            @SuppressWarnings("unchecked")
            DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll(); // 为什么能拿到?什么时候 放进去的?是weakreference回收过程中放进去的,相当于GC过程让你插入hook。那为什么被GC了还有资源泄露呢?这个问题其实是这样的,泄露是池化内存等那些需要手动释放资源。
            if (ref == null) {
                break;
            }
    
            if (!ref.dispose()) { // return allLeaks.remove(this); 所以当有人显式释放过,那么此处就返回false 就不会往下走report了
                continue;
            }
    
            String records = ref.toString();
            if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
                if (records.isEmpty()) {
                    reportUntracedLeak(resourceType);
                } else {
                    reportTracedLeak(resourceType, records);
                }
            }
        }
    }
    

    基本实现原理是:

    1. 通过DefaultResourceLeak继承自WeakReference,借助WeakReference的GC特性完成。WeakReference的GC特性是当这个对象没有被其他强引用对象引用时,仅仅被WeakReference引用(或者其他weak引用)时,会在下一次GC时回收,回收过程中会将被回收的引用放到ReferenceQueue中。此处的ReferenceQueue又是在创建DefaultResourceLeak时通过构造参数传入的。
    2. 不时poll那个ReferenceQueue队列,当拿到对象时看起dispose是否被调用过,如果没有则证明没有显示释放,则report出来。
    3. 每次创建池化buf对象时,便会创建DefaultResourceLeak,并在touch等API中调用其record方法,追踪其申请使用的地方。在开启了泄露追踪后,buf会被包装,比如包装成AdvancedLeakAwareByteBuf。
    4. 侦测reportLeak不是每次都调用,当小雨PARANOID级别是在申请buf时按随机数比例调。PARANOID级别是全调。

    此处资源泄露,是指那种需要手动释放的资源,因为引用他的对象已经不在程序逻辑中使用了,那么最终会被GC回收,但是那种需要手动释放的资源不显式释放就泄露了。比如内存池,比方说里面有5个杯子,你用的buf指向一个杯子被你占着,你不用时没显式告诉内存池说这个杯子不用了,那么就一直占着,但是buf对象不用了会被GC回收,那么此时内存池资源就泄露了。

  • 相关阅读:
    js的继承实现方式
    jdbc调用通用存储过程完成分页
    最近在忙些什么......
    【转】说服下属的“攻心术”
    设计模式原则详解
    【转】职场学做“功夫熊猫”
    内核初始化优化宏 ,初始化顺序, __init,__devexit等
    Linux 嵌入式启动以及优化
    每个程序员都该知道的10大编程格言
    linux 用户空间 和 内核空间 延时函数
  • 原文地址:https://www.cnblogs.com/simoncook/p/11980170.html
Copyright © 2011-2022 走看看