这是一段 GC 测试的代码:
public class GCTest {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
System.out.println("初始空闲内存:" + getFreeMemory(runtime.freeMemory()));
ArrayList<Object> list = new ArrayList<>(10000000);
ArrayList<Object> list2 = list;
System.out.println("创建一个一千万大小的数组列表对象后,空闲内存:" + getFreeMemory(runtime.freeMemory()));
for (int i = 0; i < 10000000; i++) {
list.add(new Object());
}
System.out.println("给数组中每个位置添加一个对象后,空闲内存:" + getFreeMemory(runtime.freeMemory()));
System.gc();
System.out.println("手动调用 GC 后,空闲内存:" + getFreeMemory(runtime.freeMemory()));
list = null;
System.gc();
System.out.println("置数组对象为 null,手动调用 GC 后,空闲内存:" + getFreeMemory(runtime.freeMemory()));
// System.out.println(list2 == null);
}
public static long getFreeMemory(long freeMemory) {
return freeMemory/1024/1024;
}
}
在 System.out.println(list2 == null);
被注释掉以后的结果:
初始空闲内存:237
创建一个一千万大小的数组列表对象后,空闲内存:199
给数组中每个位置添加一个对象后,空闲内存:157
手动调用 GC 后,空闲内存:157
置数组对象为 null,手动调用 GC 后,空闲内存:338
注释去掉后的结果:
初始空闲内存:237
创建一个一千万大小的数组列表对象后,空闲内存:199
给数组中每个位置添加一个对象后,空闲内存:157
手动调用 GC 后,空闲内存:156
置数组对象为 null,手动调用 GC 后,空闲内存:144
false
可以看到注释前后,gc 回收是不一样的。
问题:list 和 list2 同时指向这一个数组对象,按跟搜索算法来讲,list 和 list2 都可以作为 GC roots,只要不是 list = null 和 list2 = null 同时发生,数组对象就不会被回收,那为什么上面第一种情况,只有 list = null,数组对象却被回收了呢?list2 还指向这块区域的啊。
悬空的变量list2会在编译后被优化掉。
在注释掉的情况下,用Byte Code Viewer 反编译编译出来的class文件:
可以看到,这里已没有list2这个变量了。