¿Es posible atrapar la excepción de memoria en java?

Estoy desarrollando un progtwig que requeriría una gran cantidad de memoria, y quiero ver cuándo ocurre la excepción de falta de memoria. Había escuchado que esto no era posible, pero curioso si hay algún desarrollo en este sentido.

No es una excepción; es un error: java.lang.OutOfMemoryError

Puedes atraparlo a medida que desciende de Throwable:

try { // create lots of objects here and stash them somewhere } catch (OutOfMemoryError E) { // release some (all) of the above objects } 

Sin embargo, a menos que esté haciendo algo bastante específico (asignando toneladas de cosas dentro de una sección específica del código, por ejemplo) probablemente no podrá atraparlo, ya que no sabrá de dónde será lanzado.

Es posible:

 try { // tragic logic created OOME, but we can blame it on lack of memory } catch(OutOfMemoryError e) { // but what the hell will you do here :) } finally { // get ready to be fired by your boss } 

Puede atrapar e intentar recuperarse de excepciones OutOfMemoryError (OOM), PERO PROBABLEMENTE ES UNA MALA IDEA … especialmente si su objective es que la aplicación “continúe”.

Hay un número de razones para esto:

  1. Como han señalado otros, hay mejores formas de administrar los recursos de la memoria que liberar cosas explícitamente; es decir, utilizando SoftReference y WeakReference para objetos que podrían liberarse si la memoria es corta.

  2. Si espera hasta que realmente se quede sin memoria antes de liberar cosas, es probable que la aplicación pase más tiempo ejecutando el recolector de elementos no utilizados. Dependiendo de su versión de JVM y de los parámetros de ajuste de su GC, la JVM puede terminar ejecutando el GC cada vez más a medida que se aproxima al punto en el que arrojará un OOM. La ralentización (en términos de la aplicación que realiza un trabajo útil) puede ser significativa. Probablemente quieras evitar esto.

  3. Si la causa raíz de su problema es una pérdida de memoria, es probable que la captura y recuperación del OOM no recupere la memoria filtrada. Tu aplicación seguirá funcionando un poco más que OOM una y otra vez, y otra vez a intervalos cada vez menores.

Así que mi consejo NO es intentar continuar desde un OOM … a menos que sepas :

  • dónde y por qué sucedió el OOM,
  • que no habrá habido ningún “daño colateral”, y
  • que su recuperación liberará suficiente memoria para continuar.

Simplemente lanzando esto para todos aquellos que reflexionan sobre por qué alguien se está quedando sin memoria: estoy trabajando en un proyecto que se queda sin memoria con frecuencia y he tenido que implementar una solución para esto.

el proyecto es un componente de una aplicación de investigación y forense. después de recostackr datos en el campo (usando muy poca huella de memoria, por cierto) se abren los datos en nuestra aplicación de investigación. una de las características es realizar un recorrido de CFG de cualquier imagen binaria arbitraria que se capturó en el campo (aplicaciones de la memoria física). estos recorridos pueden llevar mucho tiempo, pero producen representaciones visuales muy útiles del binario que se atravesó.

para acelerar el proceso transversal, tratamos de mantener tantos datos en la memoria física como sea posible, pero las estructuras de datos crecen a medida que crece el binario y no podemos mantenerlo TODO en la memoria (el objective es usar un montón de Java de menos de 256 m). ¿entonces qué hago?

Creé versiones respaldadas por disco de LinkedLists, Hashtables, etc. Estas son reemplazos para sus contrapartes e implementan todas las mismas interfaces para que se vean idénticas desde el mundo exterior.

¿la diferencia? estas estructuras de reemplazo cooperan entre sí, eliminando errores de memoria y solicitando que los elementos usados ​​menos recientemente de la colección utilizada menos recientemente sean liberados de la memoria. Al liberar el elemento, lo vuelca en el disco en un archivo temporal (en el directorio temporal provisto por el sistema) y marca los objetos de marcador de posición como “paginado” en la colección adecuada.

hay MUCHAS razones por las que puede quedarse sin memoria en una aplicación Java; la raíz de la mayoría de estas razones es una o ambas: 1. La aplicación se ejecuta en una máquina con recursos limitados (o intenta limitar el uso de recursos limitando el tamaño del almacenamiento dynamic) ) 2. La aplicación simplemente requiere grandes cantidades de memoria (se sugirió la edición de imágenes, pero ¿qué hay de audio y video? ¿Qué pasa con los comstackdores en mi caso? ¿Qué hay de los recostackdores de datos a largo plazo sin almacenamiento no volátil?)

-poco

Es posible detectar un OutOfMemoryError (es un Error , no una Exception ), pero debe tener en cuenta que no hay forma de obtener un comportamiento definido.
Incluso puede obtener otro OutOfMemoryError mientras intenta atraparlo.

Entonces, la mejor manera es crear / usar memorias cachés con memoria. Existen algunos marcos (por ejemplo, JCS ), pero puede construir fácilmente los suyos utilizando SoftReference . Hay un pequeño artículo sobre cómo usarlo aquí . Siga los enlaces en el artículo para obtener más información.

Probablemente haya al menos un buen momento para atrapar un OutOfMemoryError, cuando está asignando específicamente algo que podría ser demasiado grande:

 public static int[] decode(InputStream in, int len) throws IOException { int result[]; try { result = new int[len]; } catch (OutOfMemoryError e) { throw new IOException("Result too long to read into memory: " + len); } catch (NegativeArraySizeException e) { throw new IOException("Cannot read negative length: " + len); } ... } 

Es posible, pero si te quedas sin montón no es muy útil. Si hay recursos que pueden liberarse, es mejor utilizar SoftReference o WeakReference para dichos recursos y su limpieza será automática.

Me ha resultado útil si se queda sin memoria directa antes de que esto no active automáticamente un GC por algún motivo. Así que he tenido motivos para forzar un gc si no puedo asignar un búfer directo.

Claro, se permite capturar OutOfMemoryError. Asegúrese de tener un plan de qué hacer cuando suceda. Necesitará liberar algo de memoria (dejando caer las referencias a los objetos) antes de asignar más objetos, o simplemente se quedará sin memoria de nuevo. A veces, el mero hecho de desenrollar la stack unos pocos marcos hará eso por ti, algunas veces necesitas hacer algo más explícito.

Es posible capturar Cualquier excepción. Solo escribe

 try{ // code which you think might throw exception }catch(java.lang.Throwable t){ // you got the exception. Now what?? } 

Idealmente, no se supone que atrape las excepciones java.lang.Error . No capturar tales excepciones y dejar que la aplicación finalice podría ser la mejor solución cuando ocurra. Si crees que puedes manejar estos errores, sigue adelante.