2013-03-05 15 views
11

Supponiamo che io ho il seguente codice:Java Garbage Collection su array stack-based

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

Supponendo che i dati non viene fatto riferimento in qualsiasi altra parte del programma, è la JVM abbastanza intelligente per consentire i dati da spazzatura raccolto mentre il processo lungo è ancora in esecuzione?

In caso contrario, sarà l'aggiunta di

data = null; 

prima del lungo processo di permettere che ciò accada?

+0

forse, probabilmente. – Cubic

+0

Si potrebbe semplicemente circondare il codice con parentesi. – MikeTheLiar

+0

'data = null' lo rende idoneo alla raccolta differenziata. –

risposta

6

Dipende dalla JVM. Le versioni di Oracle JVM che ho provato (1.6.0_41 e 1.7.0_09) non eseguono questa ottimizzazione di default. Tuttavia, 1.7.0_09 lo esegue quando si attivano le ottimizzazioni aggressive.

Ecco è il test che ho condotto:

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

Utilizzando JVM 1.7 con le impostazioni predefinite, f1() corre costantemente la memoria dopo 3195 iterazioni, mentre f2() gestisce costantemente 3205 iterazioni.

L'immagine cambia se il codice viene eseguito utilizzando Java 1.7.0_09 con -XX:+AggressiveOpts -XX:CompileThreshold=1: entrambe le versioni possono eseguire iterazioni 3205, a indicare che in questo caso HotSpot esegue l'ottimizzazione. Java 1.6.0_41 non sembra farlo.

Nel mio test, restringere l'ambito dell'array ha lo stesso effetto dell'impostazione del riferimento null e probabilmente dovrebbe essere la scelta preferita se si ritiene che si dovrebbe aiutare la JVM a raccogliere l'array al più presto.

+0

Hai provato a giocare con le bandiere opts aggressivi? – radai

+0

@radai: Quale bandiere hai in mente? – NPE

+0

-XX: + AggressiveOpts -XX: CompileThreshold = 1 principalmente, per provare e obbligarlo a compilare e ottimizzare – radai

0

Se non ci sono riferimenti ai dati, GC farà il lavoro.

+0

Questo non risponde alla domanda. edit: I am not the downvoter by the way :) –

+0

Quello che sta dicendo è che un riferimento alla matrice esiste all'interno dell'ambito, ma non è usato per il resto dell'esecuzione (a lunga esecuzione) del programma. Credo che la questione potrebbe essere meglio formulata: "i dati possono essere garbage collection se un riferimento esiste ma è inutilizzato" – asteri

1

Dato il codice come scritto, l'array non sarà certo garbage collector durante l'esecuzione longprocess(), poiché è ancora presente un riferimento di ambito alla matrice nello stack. Una volta che tale array è stato dichiarato, non sarà idoneo per la garbage collection finché tutti i riferimenti a esso non saranno stati rimossi. La tua linea

data = null; 

rimuoverà un riferimento ad esso, anche se a seconda del codice di elaborazione potrebbe non essere l'unico riferimento. Se tutti i riferimenti sono stati rimossi, il garbage collector può raccogliere molto bene la memoria dell'array entro il tempo in cui restituisce longprocess(), sebbene ciò non sia garantito.

0

L'array di dati verrà deallocato con la memoria solo al termine del processo. Quindi, se si desidera che il compilatore dealloghi la memoria, sarà necessario aggiungere esplicitamente data = null nel codice.

Il Garbage Collector libera solo la memoria che non ha un riferimento valido disponibile e non c'è altro modo per puntare di nuovo a quella memoria.