今天逛博客,看到了一个关于一个对象有没有必要手动赋值为null
的问题,捋了捋思路,决定写个测试代码来实践一下。
百说不如一用,直接上代码:
1 | public class Test1 { |
运行程序前,可以将JVM参数设置为如下:
-verbose:gc
-XX:+PrintGCDetails
控制台部分输出结果如下:
1 | [GC (System.gc()) [PSYoungGen: 3932K->744K(76288K)] 69468K->66288K(251392K), 0.0016500 secs] [Times: user=0.00 sys=0.03, real=0.00 secs] |
根据ParOldGen: 65544K->66145K(175104K)可以看出,bytes对象并没有因为没有使用而被gc回收。
1 | public class Test2 { |
控制台输出结果如下:
1 | [GC (System.gc()) [PSYoungGen: 3932K->776K(76288K)] 69468K->66320K(251392K), 0.0013737 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] |
可以看出,根据gc日志[ParOldGen: 65544K->66145K(175104K)] ,gc依然没有回收bytes对象,哪怕已经不在方法区了,我们再次修改代码。
1 | public class Test3 { |
gc日志输出如下:
1 | [GC (System.gc()) [PSYoungGen: 3932K->776K(76288K)] 69468K->66320K(251392K), 0.0014193 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] |
见证奇迹的时候到,[ParOldGen: 65544K->609K(175104K)],竟然被回收了!这是为什么?当创建bytes对象的时候,那是因为当我们创建bytes对象的时候,局部变量表中当然有bytes的引用,哪怕我们没有使用,但GC roots依然存在着和bytes对象的关联。根据test2和代码test3,我们大概可以猜到如果不操作局部变量表,那么GC roots依然会保留,所以test2依然没有回收,但是到了test3,就回收了。好吧,再来一个无用的测试,我们手动赋值为null看看结果。
1 | public class TestMain { |
其实都能想到,果然被gc干掉了……当然这只是一个实验,总结性的话就不说了,反正我也说不来,不过实践出真理!