netty-ResourceLeakDetector用法测试

在netty中,只要实现了ReferenceCounted 这个接口的类,都需要保证在正确的时刻调用"release"方法,否则这个对象的引用计数无法被重置为0。最终后果是这个被使用过的对象无法返回对象池或无法释放其内部占用的内存,从而导致内存泄漏。
netty中, 即便是老手,也经常会因为对引用计数对象的不当使用导致内存泄漏,幸运的是netty也提供了检测内存泄漏的工具类ResourceLeakDetector.java,这个类的存在,也为我们排查引用计数对象的内存泄漏提供了诸多便利。
ResourceLeakDetector.java类的设计原理是:记录引用计数对象被调用时候的方法调用栈,这样,即使讨厌的内存泄漏问题发生了,开发者也可以快速定位内存泄漏的位置,最终修复内存泄漏问题。而记录方法调用栈的精髓就在于对StackTraceAccessor.java这个jdk提供的类的巧妙使用(StackTraceAccessor对象在哪个方法内部创建,方法调用栈的栈顶就记录到哪个方法),关于StackTraceAccessor.java的分析读者可以自行查询资,基本是一搜一大堆。
下文将给出一个ResourceLeakDetector类的使用例子:

import io.netty.util.ResourceLeakDetector;
import io.netty.util.ResourceLeakDetectorFactory;
import io.netty.util.ResourceLeakHint;
import io.netty.util.ResourceLeakTracker;

public class ResourceLeakDetectorTest {

    private static  TrackableObject obj = new TrackableObject();

    public static void testStackTraceA() {
        StackTraceAccessor accessor = new StackTraceAccessor();
        accessor.A();
    }
    
    public static void testStackTraceB() {
        testStackTraceB_();
    }
    
    public static void testStackTraceB_() {
        //对象StackTraceAccessor在哪个方法内部创建,方法调用栈就记录到哪个方法
        StackTraceAccessor accessor = new StackTraceAccessor();
        accessor.A();
    }


    public static void testStackTraceC() {
        StackTraceAccessor accessor = new StackTraceAccessor();
        accessor.E();
    }
    
    /**
     * 测试StackTraceElement的作用
     * @author lihong10 2019/2/27 16:50
     * @param
     * @return
     * @modificationHistory=========================逻辑或功能性重大变更记录
     * @modify by user: {修改人} 2019/2/27 16:50
     * @modify by reason:{原因}
     */
    public static  void main(String[] args) {
    
        testStackTraceA();
    
        testStackTraceB();
    
        testStackTraceC();


        testResourceLeakDetector();
        testResourceLeakDetector2();
    }



    public static class TrackableObject implements ResourceLeakHint {
        @Override
        public String toHintString() {
            return "I am a obj can be tracked";
        }
    }





    public static  void testResourceLeakDetector() {
        System.out.println();
        System.out.println("testResourceLeakDetector() called !!!");
    
        ResourceLeakDetectorFactory factory = ResourceLeakDetectorFactory.instance();
        ResourceLeakDetector<TrackableObject> detector = factory.newResourceLeakDetector(TrackableObject.class, 0);
        detector.setLevel(ResourceLeakDetector.Level.PARANOID);
    
        ResourceLeakTracker track = track(detector);
        track.record(obj);
        track.record(obj);
        track.record(obj);
        track.record(obj);
        track.record(obj);




        System.out.println(track);
        track.close(obj);
    
        System.out.println();
        System.out.println("************************************************");
        System.out.println(track);
        System.out.println();



    }

    private static ResourceLeakTracker track(ResourceLeakDetector<TrackableObject> detector) {

        ResourceLeakTracker<TrackableObject> track = detector.track(obj);
        return track;
    }



    public static  void testResourceLeakDetector2() {
        System.out.println();
        System.out.println("testResourceLeakDetector2() called !!!");
    
        ResourceLeakDetectorFactory factory = ResourceLeakDetectorFactory.instance();
        ResourceLeakDetector<TrackableObject> detector = factory.newResourceLeakDetector(TrackableObject.class, 0);
        detector.setLevel(ResourceLeakDetector.Level.PARANOID);
    
        ResourceLeakTracker track = track2(detector);
        track.record();
        track.record();
        track.record();
        track.record();
        track.record();
    
        System.out.println(track);
    
        System.out.println();
        System.out.println("************************************************");
        System.out.println(track);
        System.out.println();
    }
    
    private static ResourceLeakTracker track2(ResourceLeakDetector<TrackableObject> detector) {
    
        TrackableObject obj2 = new TrackableObject();
        ResourceLeakTracker<TrackableObject> track = detector.track(obj2);
        obj2 = null;
        return track;
    }

}




///


public  class StackTraceAccessor extends Throwable {

    public StackTraceAccessor() {
        super();
    }
    
    public void A() {
        System.out.println("method A");
        B();
    }
    
    public void B() {
        System.out.println("method B");
        C();
    }
    
    public void C() {
        System.out.println("method C");
        D();
    }
    
    public void D() {
        System.out.println("method D");
        StackTraceElement[] array = getStackTrace();
        for (StackTraceElement element : array) {
            //System.out.println(element.getClassName() + ":  " + element.getMethodName() + ": " + element.getLineNumber());
            System.out.println(element.toString());
        }
    }


    public void E() {
        System.out.println("method E");
        F();
    }
    
    public void F() {
        System.out.println("method F");
        G();
    }
    
    public void G() {
        System.out.println("method G");
        StackTraceAccessor newAccessor = new StackTraceAccessor();
        StackTraceElement[] array = newAccessor.getStackTrace();
        //这里打印的StackTraceElement是在方法G中new出来的StackTraceAccessor类型的新对象newAccessor的栈帧
        for (StackTraceElement element : array) {
            System.out.println(element.toString());
        }
    }

}
运行上述代码可以看到控制台打印如下内容,并且打印的内容的格式与所有netty中的引用计数对象内存泄漏时候的日志是相似的:

Recent access records: 
#1:
	Hint: I am a obj can be tracked
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.main(ResourceLeakDetectorTest.java:52)
Created at:
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.track(ResourceLeakDetectorTest.java:101)
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.testResourceLeakDetector(ResourceLeakDetectorTest.java:77)
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.main(ResourceLeakDetectorTest.java:52)
: 3 leak records were discarded because they were duplicates
: 1 leak records were discarded because the leak record count is targeted to 4. Use system property io.netty.leakDetection.targetRecords to increase the limit.

************************************************



testResourceLeakDetector2() called !!!
2019-03-04 18:58:14,907 DEBUG [io.netty.util.ResourceLeakDetectorFactory] - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@e2d56bf

Recent access records: 
#1:
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.main(ResourceLeakDetectorTest.java:53)
Created at:
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.track2(ResourceLeakDetectorTest.java:133)
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.testResourceLeakDetector2(ResourceLeakDetectorTest.java:115)
	com.lihong.DDPush.netty.ResourceLeakDetectorTest.main(ResourceLeakDetectorTest.java:53)
: 3 leak records were discarded because they were duplicates
: 1 leak records were discarded because the leak record count is targeted to 4. Use system property io.netty.leakDetection.targetRecords to increase the limit.

************************************************






你可能感兴趣的:(netty)