2013-03-05 9 views
11

Załóżmy, że mam następujący kod:Java Garbage Collection na na stosie Tablice

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. 
} 

Zakładając, że dane nie odwołuje się nigdzie indziej w programie, jest JVM na tyle silny, aby umożliwić dane za śmieci zbierane podczas długiego procesu nadal działa?

Jeśli nie, dodając

data = null; 

przed długi proces do tego dopuścić?

+0

może, prawdopodobnie. – Cubic

+0

Można po prostu otoczyć kod nawiasami. – MikeTheLiar

+0

'data = null' powoduje, że kwalifikuje się do zbierania śmieci. –

Odpowiedz

6

Wszystko zależy od maszyny JVM. Wersje JVM Oracle, które wypróbowałem (1.6.0_41 i 1.7.0_09), nie wykonują tej optymalizacji domyślnie. Jednak 1.7.0_09 wykonuje go, gdy włączone są agresywne optymalizacje.

Oto jest test mam przeprowadzać:

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("-----"); 
     } 
    } 
} 

Korzystanie JVM 1.7 z ustawieniami domyślnymi, f1() konsekwentnie zabraknie pamięci po 3195 iteracji, natomiast f2() konsekwentnie udaje 3205 iteracji.

Obraz zmienia się, jeśli kod jest uruchamiany przy użyciu języka Java 1.7.0_09 z -XX:+AggressiveOpts -XX:CompileThreshold=1: obie wersje mogą wykonywać iteracje 3205, wskazując, że HotSpot wykonuje tę optymalizację w tym przypadku. Java 1.6.0_41 nie wydaje się tego robić.

W moich testach ograniczenie zakresu tablicy ma taki sam skutek jak ustawienie odniesienia null, i powinno być prawdopodobnie preferowanym wyborem, jeśli uważasz, że powinieneś pomóc JVM zebrać tablicę jak najszybciej.

+0

Czy próbowałeś grać z agresywnymi flagami opts? – radai

+0

@radai: Jakie flagi masz na myśli? – NPE

+0

-XX: + AggressiveOpts -XX: CompileThreshold = 1 głównie, aby spróbować zmusić go do kompilacji i optymalizacji – radai

0

Jeśli nie ma odniesienia do danych, to GC wykona zadanie.

+0

To nie odpowiada na pytanie. edytuj: Nie jestem przygnębiającą przy okazji :) –

+0

Mówi, że odwołanie do tablicy istnieje w zasięgu, ale nie jest używane przez resztę (długotrwałego) wykonywania programu. Myślę, że pytanie mogłoby być lepiej sformułowane: "Czy dane mogą być gromadzone w śmieciach, jeśli istnieją odniesienia, ale nie są używane?" – asteri

1

Biorąc pod uwagę kod w formie pisemnej, tablica z pewnością nie zostanie usunięta podczas wykonywania procedury longprocess(), ponieważ nadal istnieje odniesienie do tablicy na stosie. Po zadeklarowaniu tej tablicy nie będzie ona mogła korzystać z funkcji czyszczenia pamięci, dopóki wszystkie odwołania do niej nie zostaną usunięte. Twoja linia zeruje jedno odniesienie, chociaż w zależności od kodu przetwarzania może nie być jedyną referencją. Jeśli wszystkie odwołania zostały usunięte, wówczas garbage collector może bardzo dobrze zebrać pamięć tablicy przez proces longprocess(), ale nie jest to gwarantowane.

0

Tablica danych zostanie zwolniona z pamięci dopiero po zakończeniu procesu. Jeśli chcesz, aby kompilator zwolnił pamięć, musisz jawnie dodać data = null do kodu.

Garbage Collector uwalnia tylko pamięć, która nie ma ważnego odniesienia i nie ma innego sposobu na wskazanie tej pamięci ponownie.