未使用的私有变量可以在其持有实例之前进行GC吗?

时间:2013-03-04 15:26:48

标签: java garbage-collection

考虑以下课程:

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是否会合同禁止它?

2 个答案:

答案 0 :(得分:2)

即使您的代码在编译时没有(似乎)访问longArr,它仍然可以通过反射随时访问,这是GC / JIT编译器无法猜测的。

唯一可以删除的未使用的变量是本地变量(可以在分配参考后立即清除它们)。事实上,Eclipse编译器甚至允许在编译时删除它们(请参阅首选项&gt; Java&gt;编译器&gt;保留未使用的局部变量)。

答案 1 :(得分:0)

longArr 不会在任何地方使用;但是您正在创建班级 MemoryTest 的对象。这意味着为每个对象初始化属性 longArr

因此,如果对类的对象的引用不为null;然后不要认为GC有这种属性的任何方法。 longArr 将永远与对象联系在一起;因此只有在对象获得GC时才能清理它。