2013-03-05 121 views
11

假设我有以下代码:Java垃圾收集

public void process() { 
    byte[] data = new byte[size]; 
    ... // code that uses the above data 
    longProcess(); // a very long running process that does not use the data. 
} 

假设在程序中的数据没有其他地方引用,足够的JVM智能允许数据是垃圾收集而漫长的过程仍在运行?

如果没有,会增加

data = null; 

的漫长过程才允许这种情况发生?

+0

。 – Cubic 2013-03-05 20:32:27

+0

你可以用括号括住代码。 – MikeTheLiar 2013-03-05 20:32:41

+0

'data = null'使其有资格被垃圾收集。 – 2013-03-05 20:32:42

回答

6

这依赖于JVM。我尝试过的Oracle JVM版本(1.6.0_41和1.7.0_09)默认情况下不会执行此优化。但是,1.7.0_09确实会在开启积极优化时执行此操作。

这里是我进行的测试:

public class Main { 
    public static int g() { 
     int n = 100000; 
     int arr[][] = new int[n][]; 
     for (int i = 0; i < n; ++i) { 
      try { 
       arr[i] = new int[100000]; 
      } catch (OutOfMemoryError ex) { 
       return i; 
      } 
     } 
     return -1; 
    } 
    public static void f1() { 
     int arr[] = new int[1000000]; 
     System.out.println(g()); 
    } 
    public static void f2() { 
     int arr[] = new int[1000000]; 
     arr = null; 
     System.out.println(g()); 
    } 
    public static void main(String[] argv) { 
     for (int j = 0; j < 2; ++j) { 
      for (int i = 0; i < 10; ++i) { 
       f1(); 
      } 
      System.out.println("-----"); 
      for (int i = 0; i < 10; ++i) { 
       f2(); 
      } 
      System.out.println("-----"); 
     } 
    } 
} 

使用JVM 1.7使用默认设置,f1()一贯内存用完之后3195次迭代,而f2()持续管理3205次迭代。如果代码是用Java 1.7.0_09运行与-XX:+AggressiveOpts -XX:CompileThreshold=1

的情况发生了变化:两个版本都可以做3205次迭代,这说明热点确实执行在这种情况下,这种优化。 Java 1.6.0_41似乎没有这样做。

在我的测试,限制阵列的范围有作为设定参考null相同的效果,而且也许应该是首选,如果你觉得你应该帮助JVM收集阵列尽快。

+0

你有没有试过玩过挑衅的选择标志? – radai 2013-03-05 20:42:25

+0

@radai:你有哪些旗帜? – NPE 2013-03-05 20:43:40

+0

-XX:+ AggressiveOpts -XX:CompileThreshold = 1主要是试图强制它编译和优化 – radai 2013-03-05 20:48:01

0

如果有数据没有引用,那么GC将做的工作。

+0

这不回答问题。编辑:我不是downvoter顺便说一句:) – 2013-03-05 20:36:03

+0

他说的是,对数组的引用存在于范围内,但它不用于程序的其余部分(长时间运行)。我认为这个问题可以更好地表达为:“如果存在引用但未被使用,数据是否可以被垃圾收集?” – asteri 2013-03-05 20:37:30

1

鉴于如编写的代码,该数组将肯定不会被垃圾longprocess()执行期间收集的,因为仍然有作用域参考堆栈上的阵列。一旦该数组已被声明,它将不会有资格进行垃圾收集,直到所有对它的引用都被删除。您的线路

data = null; 

将删除对它的一个引用,但取决于您的处理代码,它可能不是唯一的引用。如果所有引用都被删除了,那么垃圾收集器可能会在longprocess()返回时很好地收集该数组的内存,尽管这是不能保证的。

0

在处理方法结束后,数据数组将只能用内存释放。所以,如果你想让编译器解除分配内存,那么你将不得不在代码中明确添加data = null。

垃圾收集器只释放没有可用的有效引用的内存,并且没有其他方法可以再次指向该内存。或许,可能是