2013-03-05 322 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。

垃圾收集器只釋放沒有可用的有效引用的內存,並且沒有其他方法可以再次指向該內存。或許,可能是