考虑以下课程:
public class MemoryTest
{
private long[] longArr; // Eclipse marks this unused
public MemoryTest(int arrSize) {
longArr = new long[arrSize*10];
}
public static void main(String[] args) {
int numObjs = 10000;
MemoryTest[] mts = new MemoryTest[numObjs];
for(int i = 0; i < numObjs; i++) {
// build a large number of objects which hold expensive, unused references
mts[i] = new MemoryTest(i);
//System.gc(); interestingly, uncommenting this line causes OOM earlier
System.out.println("Built "+i+": "+Runtime.getRuntime().freeMemory()/1024+"KB");
}
System.out.println(Arrays.hashCode(mts)); // so elements cannot be GCed earlier
}
}
这样就失败了:
... truncated output ...
Built 5236: 62070KB
Built 5237: 61661KB
Built 5238: 61252KB
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at MemoryTest.<init>(MemoryTest.java:6)
at MemoryTest.main(MemoryTest.java:15)
显然这是一个人为的例子,但我想知道GC / JIT编译器是否能够整理这个对象,因为longArr
并未在任何地方使用。从Java 7开始,它似乎现在还没有整理,但是如果编译器变得更聪明,或者我们以某种方式改变了这个例子,那么JVM是否会合同禁止它?
答案 0 :(得分:2)
即使您的代码在编译时没有(似乎)访问longArr
,它仍然可以通过反射随时访问,这是GC / JIT编译器无法猜测的。
唯一可以删除的未使用的变量是本地变量(可以在分配参考后立即清除它们)。事实上,Eclipse编译器甚至允许在编译时删除它们(请参阅首选项&gt; Java&gt;编译器&gt;保留未使用的局部变量)。
答案 1 :(得分:0)
longArr 不会在任何地方使用;但是您正在创建班级 MemoryTest 的对象。这意味着为每个对象初始化属性 longArr 。
因此,如果对类的对象的引用不为null;然后不要认为GC有这种属性的任何方法。 longArr 将永远与对象联系在一起;因此只有在对象获得GC时才能清理它。