usegcoverheadlimit outofmemoryerror exceeded java garbage-collection

outofmemoryerror - Colección de basura de Java en matrices basadas en pila



jvm options (4)

Dado el código tal como está escrito, la matriz ciertamente no será recolectada durante la ejecución de longprocess (), ya que todavía hay una referencia del alcance de la matriz en la pila. Una vez que esa matriz ha sido declarada, no será elegible para la recolección de basura hasta que se hayan eliminado todas las referencias a la misma. Tu linea

data = null;

eliminará una referencia a ella, aunque dependiendo de su código de procesamiento, puede que no sea la única referencia. Si se han eliminado todas las referencias, entonces el recolector de basura puede muy bien recolectar la memoria de esa matriz para cuando longprocess () regrese, aunque esto no está garantizado.

Supongamos que tengo el siguiente código:

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

Suponiendo que los datos no se mencionan en ningún otro lugar en el programa, ¿la JVM es lo suficientemente inteligente como para permitir que los datos sean basura recolectados mientras el largo proceso todavía se está ejecutando?

Si no, agregará

data = null;

antes del largo proceso, ¿permite que esto suceda?


Esto depende de la JVM. Las versiones de JVM de Oracle que he probado (1.6.0_41 y 1.7.0_09) no realizan esta optimización de forma predeterminada. Sin embargo, 1.7.0_09 lo realiza cuando las optimizaciones agresivas están activadas.

Esta es la prueba que realicé:

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

Al usar JVM 1.7 con las configuraciones predeterminadas, f1() queda constantemente sin memoria después de 3195 iteraciones, mientras que f2() gestiona consistentemente 3205 iteraciones.

La imagen cambia si el código se ejecuta utilizando Java 1.7.0_09 con -XX:+AggressiveOpts -XX:CompileThreshold=1 : ambas versiones pueden hacer 3205 iteraciones, lo que indica que HotSpot realiza esta optimización en este caso. Java 1.6.0_41 no parece hacer esto.

En mis pruebas, restringir el alcance de la matriz tiene el mismo efecto que establecer la referencia null , y probablemente sea la opción preferida si cree que debería ayudar a la JVM a recopilar la matriz lo antes posible.


La matriz de datos solo se desasignará con la memoria una vez que el método de proceso haya finalizado. Entonces, si quiere que el compilador desasigne la memoria, tendrá que agregar explícitamente data = null en el código.

El recolector de basura solo libera memoria que no tiene una referencia válida disponible y no hay otra manera de apuntar a esa memoria nuevamente.


Si no hay referencia a los datos, GC hará el trabajo.