¿Detectando java.lang.OutOfMemoryError?

101

Documentación para java.lang.Errordice:

Un error es una subclase de Throwable que indica problemas graves que una aplicación razonable no debería intentar detectar.

Pero como java.lang.Errores una subclase de java.lang.Throwable, puedo atrapar este tipo de Throwable.

Entiendo por qué no es una buena idea detectar este tipo de excepción. Por lo que tengo entendido, si decidimos capturarlo, el controlador de captura no debería asignar memoria por sí mismo. De OutOfMemoryErrorlo contrario , se volverá a lanzar.

Entonces, mi pregunta es:

  1. ¿Existen escenarios del mundo real en los que la captura java.lang.OutOfMemoryErrorpodría ser una buena idea?
  2. Si decidimos capturar java.lang.OutOfMemoryError, ¿cómo podemos asegurarnos de que el controlador de captura no asigne memoria por sí mismo (herramientas o mejores prácticas)?
Denis Bazhenov
fuente
Para su primera pregunta, agregaré que detectaré el OutOfMemoryError para (al menos intentar) notificar al usuario del problema. Anteriormente, la cláusula catch (Exception e) no detectaba el error y no se mostraba ningún comentario al usuario.
Josep Rodríguez López
1
Hay casos específicos, por ejemplo, la asignación de una matriz gigantesca, donde uno puede detectar el error OOM alrededor de esa operación y recuperarse razonablemente bien. Pero colocar el try / catch alrededor de una gran cantidad de código e intentar recuperarse limpiamente y continuar es probablemente una mala idea.
Hot Licks
Véase también stackoverflow.com/questions/14376924/…
Raedwald

Respuestas:

85

Estoy de acuerdo y en desacuerdo con la mayoría de las respuestas aquí.

Hay una serie de escenarios en los que es posible que desee captar una OutOfMemoryErrory, en mi experiencia (en Windows y Solaris JVM), muy pocas veces es OutOfMemoryErrorla sentencia de muerte para una JVM.

Solo hay una buena razón para detectar un OutOfMemoryErrorerror y es cerrar con elegancia, liberar recursos de manera limpia y registrar la razón del error lo mejor que pueda (si aún es posible hacerlo).

En general, OutOfMemoryErrorocurre debido a una asignación de memoria de bloque que no se puede satisfacer con los recursos restantes del montón.

Cuando Errorse lanza, el montón contiene la misma cantidad de objetos asignados que antes de la asignación fallida y ahora es el momento de eliminar las referencias a los objetos en tiempo de ejecución para liberar aún más memoria que puede ser necesaria para la limpieza. En estos casos, incluso puede ser posible continuar, pero definitivamente sería una mala idea ya que nunca puede estar 100% seguro de que la JVM está en un estado reparable.

Demostración que OutOfMemoryErrorno significa que la JVM no tenga memoria en el bloque de captura:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" + maxMemory + "M");
        }
    }
}

Salida de este código:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

Si ejecuto algo crítico, generalmente lo capturo Error, lo registro en syserr, luego lo registro usando el marco de registro de mi elección, luego procedo a liberar recursos y cerrarlo de manera limpia. ¿Qué es lo peor que puede pasar? La JVM está muriendo (o ya está muerta) de todos modos y al detectarla Errorhay al menos una posibilidad de limpieza.

La advertencia es que debe apuntar a la detección de este tipo de errores solo en lugares donde la limpieza es posible. No te pongas mantas en catch(Throwable t) {}todas partes o tonterías como esa.

Chris
fuente
De acuerdo, publicaré mi experimento con una nueva respuesta.
Mister Smith
4
"nunca puede estar 100% seguro de que la JVM está en un estado reparable": porque es OutOfMemoryErrorposible que se haya lanzado desde un punto que haya colocado su programa en un estado inconsistente, porque se puede lanzar en cualquier momento. Ver stackoverflow.com/questions/8728866/…
Raedwald
En OpenJdk1.7.0_40, no obtengo ningún error o excepción cuando ejecuto este código. Incluso cambié el MEGABYTE a GIGABYTE (1024 * 1024 * 1024). ¿Es eso porque el optimizador elimina la variable 'byte [] bytes' ya que no se usa en el resto del código?
RoboAlex
"Hay una serie de escenarios en los que es posible que desee detectar un OutOfMemoryError" frente a "Sólo hay una buena razón para detectar un OutOfMemoryError" . ¡¡¡Decídete!!!
Stephen C
3
Escenario del mundo real en el que PUEDE querer detectar el error OutOfMemory: cuando se produce al intentar asignar una matriz con más de 2G elementos. El nombre del error es un nombre poco apropiado en este caso, pero sigue siendo un OOM.
Charles Roth
31

Usted puede recuperarse de ella:

package com.stackoverflow.q2679330;

public class Test {

    public static void main(String... args) {
        int size = Integer.MAX_VALUE;
        int factor = 10;

        while (true) {
            try {
                System.out.println("Trying to allocate " + size + " bytes");
                byte[] bytes = new byte[size];
                System.out.println("Succeed!");
                break;
            } catch (OutOfMemoryError e) {
                System.out.println("OOME .. Trying again with 10x less");
                size /= factor;
            }
        }
    }

}

¿Pero tiene sentido? ¿Qué más te gustaría hacer? ¿Por qué inicialmente asignaría tanta memoria? ¿También está bien tener menos memoria? ¿Por qué no lo usas de todos modos? O si eso no es posible, ¿por qué no darle más memoria a la JVM desde el principio?

De vuelta a tus preguntas:

1: ¿Existe algún escenario de palabras reales cuando la captura de java.lang.OutOfMemoryError puede ser una buena idea?

Ninguno me viene a la mente.

2: si detectamos java.lang.OutOfMemoryError, ¿cómo podemos estar seguros de que el controlador de captura no asigna memoria por sí mismo (herramientas o mejores prácticas)?

Depende de lo que haya provocado el OOME. Si se declara fuera del trybloque y sucedió paso a paso, entonces sus posibilidades son pocas. Es posible que desee reservar algo de espacio en la memoria de antemano:

private static byte[] reserve = new byte[1024 * 1024]; // Reserves 1MB.

y luego ajústelo a cero durante OOME:

} catch (OutOfMemoryException e) {
     reserve = new byte[0];
     // Ha! 1MB free!
}

Por supuesto, esto lo hace todo sin sentido;) Simplemente dé a JVM suficiente memoria según lo requiera su aplicación. Ejecute un generador de perfiles si es necesario.

BalusC
fuente
1
Sin embargo, incluso reservar espacio no garantiza una solución funcional. Ese espacio también podría estar ocupado por algún otro hilo;)
Wolph
@Wolph: ¡Entonces dale más memoria a la JVM! O_o Todo con todo, de hecho no tiene sentido;)
BalusC
2
El primer fragmento funciona porque el objeto que desencadenó el error es un único objeto GRANDE (la matriz). Cuando se alcanza la cláusula catch, la JVM que consume mucha memoria la recopila. Si estaba utilizando el mismo objeto fuera del bloque try, o en otro hilo, o en la misma captura, JVM no lo recopila, por lo que es imposible crear un nuevo objeto único de ningún tipo. el segundo fragmento, por ejemplo, puede no funcionar.
Mister Smith
3
¿Por qué no simplemente configurarlo null?
Pacerier
1
@MisterSmith Tu comentario no tiene sentido. El objeto grande no existe. No se asignó en primer lugar: activó el OOM, por lo que ciertamente no necesita GC.
Marqués de Lorne
15

En general, es una mala idea intentar detectar y recuperarse de un OOM.

  1. Un OOME también podría haberse lanzado a otros hilos, incluidos los hilos que su aplicación ni siquiera conoce. Cualquiera de estos hilos ahora estará muerto, y cualquier cosa que estuviera esperando una notificación podría quedarse bloqueada para siempre. En resumen, su aplicación podría romperse terminalmente.

  2. Incluso si se recupera con éxito, su JVM aún puede estar sufriendo de inanición y su aplicación funcionará de manera abismal como resultado.

Lo mejor que se puede hacer con un OOME es dejar morir la JVM.

(Esto supone que la JVM hace morir. Por ejemplo, Ooms en un hilo servlet Tomcat no matan a la JVM, y esto lleva a la Tomcat entrar en un estado catatónico en el que no responderá a ninguna solicitud ... ni siquiera pide a reiniciar.)

EDITAR

No estoy diciendo que sea una mala idea detectar OOM en absoluto. Los problemas surgen cuando intenta recuperarse del OOME, ya sea deliberadamente o por descuido. Siempre que detecte un OOM (directamente o como un subtipo de Error o Throwable), debe volver a lanzarlo o hacer que la aplicación / JVM salga.

Aparte: Esto sugiere que para una máxima robustez frente a los OOM, una aplicación debería usar Thread.setDefaultUncaughtExceptionHandler () para establecer un controlador que hará que la aplicación salga en caso de un OOME, sin importar en qué hilo se ejecute el OOME. Me interesaría conocer opiniones sobre esto ...

El único otro escenario es cuando se sabe con certeza que el OOM no ha provocado ningún daño colateral; es decir, sabes:

  • qué causó específicamente el OOME,
  • lo que estaba haciendo la aplicación en ese momento, y que está bien simplemente descartar ese cálculo, y
  • que un OOME (aproximadamente) simultáneo no puede haber ocurrido en otro hilo.

Hay aplicaciones en las que es posible saber estas cosas, pero para la mayoría de las aplicaciones no puede estar seguro de que la continuación después de un OOME sea segura. Incluso si empíricamente "funciona" cuando lo prueba.

(El problema es que se requiere una prueba formal para demostrar que las consecuencias de los OOME "anticipados" son seguras y que los OOME "no anticipados" no pueden ocurrir dentro del control de un OOME try / catch).

Stephen C
fuente
Sí estoy de acuerdo con usted. En general, es mala idea. ¿Pero entonces por qué tengo la posibilidad de atraparlo? :)
Denis Bazhenov
@dotsid - 1) porque hay casos en los que debería detectarlo, y 2) porque hacer imposible la captura de OOM tendría un impacto negativo en el lenguaje y / o en otras partes del tiempo de ejecución de Java.
Stephen C
1
Dices: "porque hay casos en los que debes cogerlo". Entonces esto fue parte de mi pregunta original. ¿Cuáles son los casos en los que quiere atrapar a OOME?
Denis Bazhenov
1
@dotsid: vea mi respuesta editada. El único caso en el que puedo pensar para detectar OOM es cuando necesita hacer esto para forzar a una aplicación de subprocesos múltiples a salir en caso de un OOM. Quizás desee hacer esto para todos los subtipos de Error.
Stephen C
1
No se trata solo de detectar OOMEs. También necesitas recuperarte de ellos. ¿Cómo se recupera un hilo si se suponía que debía (decir) notificar a otro hilo ... pero obtuvo un OOME? Seguro, la JVM no morirá. Pero es probable que la aplicación deje de funcionar debido a los subprocesos atascados esperando notificaciones de subprocesos que se reiniciaron debido a la captura de un OOME.
Stephen C
14

Sí, hay escenarios del mundo real. Aquí está el mío: necesito procesar conjuntos de datos de muchos elementos en un clúster con memoria limitada por nodo. Una instancia de JVM determinada pasa por muchos elementos uno tras otro, pero algunos de los elementos son demasiado grandes para procesarlos en el clúster: puedo detectar OutOfMemoryErrory tomar nota de qué elementos son demasiado grandes. Más tarde, puedo volver a ejecutar solo los elementos grandes en una computadora con más RAM.

(Debido a que es una única asignación de varios gigabytes de una matriz que falla, la JVM aún está bien después de detectar el error y hay suficiente memoria para procesar los otros elementos).

Michael Kuhn
fuente
¿Entonces tienes un código como byte[] bytes = new byte[length]? ¿Por qué no verificar sizeen un punto anterior?
Raedwald
1
Porque lo mismo sizeestará bien con más memoria. Paso por la excepción porque en la mayoría de los casos todo estará bien.
Michael Kuhn
10

Definitivamente hay escenarios en los que atrapar un OOME tiene sentido. IDEA los detecta y abre un cuadro de diálogo que le permite cambiar la configuración de la memoria de inicio (y luego sale cuando haya terminado). Un servidor de aplicaciones podría detectarlos e informarlos. La clave para hacer esto es hacerlo a un alto nivel en el envío para que tenga una posibilidad razonable de tener una gran cantidad de recursos liberados en el punto en el que está detectando la excepción.

Además del escenario IDEA anterior, en general, la captura debe ser Throwable, no solo OOM específicamente, y debe realizarse en un contexto donde al menos el hilo terminará en breve.

Por supuesto, la mayoría de las veces la memoria se muere de hambre y la situación no se puede recuperar, pero hay formas en que tiene sentido.

Yishai
fuente
8

Me encontré con esta pregunta porque me preguntaba si es una buena idea detectar OutOfMemoryError en mi caso. Estoy respondiendo aquí parcialmente para mostrar otro ejemplo más cuando detectar este error puede tener sentido para alguien (es decir, para mí) y parcialmente para averiguar si es una buena idea en mi caso (siendo yo un desarrollador súper junior que nunca puedo estar demasiado seguro de cualquier línea de código que escriba).

De todos modos, estoy trabajando en una aplicación de Android que se puede ejecutar en diferentes dispositivos con diferentes tamaños de memoria. La parte peligrosa es decodificar un mapa de bits de un archivo y mostrarlo en una instancia de ImageView. No quiero restringir los dispositivos más potentes en términos del tamaño del mapa de bits decodificado, ni puedo estar seguro de que la aplicación no se ejecutará en un dispositivo antiguo con el que nunca me he encontrado con muy poca memoria. Por eso hago esto:

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
bitmapOptions.inSampleSize = 1;
boolean imageSet = false;
while (!imageSet) {
  try {
    image = BitmapFactory.decodeFile(filePath, bitmapOptions);
    imageView.setImageBitmap(image); 
    imageSet = true;
  }
  catch (OutOfMemoryError e) {
    bitmapOptions.inSampleSize *= 2;
  }
}

De esta forma logro proporcionar dispositivos cada vez menos potentes según sus, o más bien las necesidades y expectativas de sus usuarios.

Maria
fuente
1
Otra opción sería calcular el tamaño de los mapas de bits que puede manejar en lugar de intentarlo y fallar. "Las excepciones deben usarse para casos excepcionales", creo que alguien dijo. Pero diré que su solución parece ser la salida más fácil, quizás no la mejor, pero probablemente la más fácil.
jontejj
Depende del códec. Imagine que un bmp de 10 MB probablemente resulte en sólo un poco más de 10 MB de pila, mientras que un archivo JPEG de 10 MB "explotará". Lo mismo en mi caso donde quiero analizar un XML que puede variar enormemente dependiendo de la complejidad del contenido
Daniel Alder
5

Sí, la verdadera pregunta es "¿qué vas a hacer en el controlador de excepciones?" Para casi cualquier cosa útil, asignará más memoria. Si desea realizar algún trabajo de diagnóstico cuando se produce un OutOfMemoryError, puede utilizar el enlace -XX:OnOutOfMemoryError=<cmd>proporcionado por HotSpot VM. Ejecutará su (s) comando (s) cuando ocurra un OutOfMemoryError, y usted puede hacer algo útil fuera del montón de Java. En primer lugar, realmente desea evitar que la aplicación se quede sin memoria, por lo que averiguar por qué sucede es el primer paso. Luego, puede aumentar el tamaño de pila de MaxPermSize según corresponda. Aquí hay algunos otros ganchos útiles de HotSpot:

-XX:+PrintCommandLineFlags
-XX:+PrintConcurrentLocks
-XX:+PrintClassHistogram

Vea la lista completa aquí

Rob Heiser
fuente
Es incluso peor de lo que piensas. Debido a que OutOfMemeoryError se puede lanzar un en cualquier punto de su programa (no solo desde una newdeclaración), su programa estará en un estado indefinido cuando capture la excción.
Raedwald
5

Tengo una aplicación que necesita recuperarse de fallas de OutOfMemoryError, y en programas de un solo subproceso siempre funciona, pero a veces no funciona en programas de subprocesos múltiples. La aplicación es una herramienta de prueba Java automatizada que ejecuta secuencias de prueba generadas con la máxima profundidad posible en las clases de prueba. Ahora, la interfaz de usuario debe ser estable, pero el motor de prueba puede quedarse sin memoria mientras crece el árbol de casos de prueba. Manejo esto con el siguiente tipo de código idiomático en el motor de prueba:

boolean isOutOfMemory = falso; // bandera utilizada para informar
tratar {
   SomeType largeVar;
   // Bucle principal que asigna cada vez más a largeVar
   // puede terminar OK, o generar OutOfMemoryError
}
catch (OutOfMemoryError ex) {
   // largeVar ahora está fuera de alcance, también lo está la basura
   System.gc (); // limpiar datos de largeVar
   isOutOfMemory = verdadero; // bandera disponible para su uso
}
// programa prueba la bandera para informar la recuperación

Esto funciona siempre en aplicaciones de un solo subproceso. Pero recientemente puse mi motor de prueba en un hilo de trabajo separado de la interfaz de usuario. Ahora, la falta de memoria puede ocurrir arbitrariamente en cualquiera de los subprocesos, y no tengo claro cómo detectarla.

Por ejemplo, hice que el OOME ocurriera mientras los fotogramas de un GIF animado en mi interfaz de usuario estaban siendo ciclados por un hilo propietario creado detrás de escena por una clase Swing que está fuera de mi control. Pensé que había asignado todos los recursos necesarios por adelantado, pero claramente el animador está asignando memoria cada vez que busca la siguiente imagen. Si alguien tiene una idea sobre cómo manejar los OOME planteados en cualquier hilo, me encantaría escucharla.

Tony Simons
fuente
En una aplicación de un solo subproceso, si ya no usa algunos de los nuevos objetos problemáticos cuya creación arrojó el error, estos pueden recopilarse en la cláusula catch. Sin embargo, si la JVM detecta que el objeto se puede usar más adelante, no se puede recopilar y la aplicación explota. Vea mi respuesta en este hilo.
Mister Smith
4

OOME se puede capturar, pero generalmente será inútil, dependiendo de si la JVM puede recolectar basura en algunos objetos cuando se alcanza la captura, y cuánta memoria de pila queda en ese momento.

Ejemplo: en mi JVM, este programa se ejecuta hasta su finalización:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

Sin embargo, simplemente agregando una sola línea en la captura le mostrará de qué estoy hablando:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

El primer programa funciona bien porque cuando se alcanza la captura, la JVM detecta que la lista no se va a utilizar más (esta detección también puede ser una optimización realizada en tiempo de compilación). Entonces, cuando llegamos a la declaración de impresión, la memoria del montón se ha liberado casi por completo, por lo que ahora tenemos un amplio margen de maniobra para continuar. Este es el mejor caso.

Sin embargo, si el código está organizado de forma tal que la lista llse utiliza después de que se haya capturado el OOME, la JVM no podrá recopilarlo. Esto sucede en el segundo fragmento. El OOME, desencadenado por una nueva creación Long, se detecta, pero pronto estamos creando un nuevo Objeto (una Cadena en la System.out,printlnlínea), y el montón está casi lleno, por lo que se lanza un nuevo OOME. Este es el peor de los casos: intentamos crear un nuevo objeto, fallamos, capturamos el OOME, sí, pero ahora la primera instrucción que requiere una nueva memoria de pila (por ejemplo: crear un nuevo objeto) arrojará un nuevo OOME. Piénsalo, ¿qué más podemos hacer a estas alturas con tan poca memoria ?. Probablemente solo saliendo. De ahí lo inútil.

Entre las razones por las que la JVM no recopila recursos, una es realmente aterradora: un recurso compartido con otros subprocesos que también lo utilizan. Cualquiera con cerebro puede ver lo peligroso que puede ser atrapar OOME si se inserta en alguna aplicación no experimental de cualquier tipo.

Estoy usando una JVM de Windows x86 de 32 bits (JRE6). La memoria predeterminada para cada aplicación Java es de 64 MB.

Señor smith
fuente
¿Qué pasa si lo hago ll=nulldentro del bloque de captura?
Naanavanalla
3

La única razón por la que puedo pensar en por qué detectar errores OOM podría ser que tiene algunas estructuras de datos masivas que ya no está usando, y puede configurarlas en nulo y liberar algo de memoria. Pero (1) eso significa que estás desperdiciando memoria, y deberías arreglar tu código en lugar de simplemente cojear después de un OOME, y (2) incluso si lo detectaras, ¿qué harías? OOM puede suceder en cualquier momento, potencialmente dejando todo a medio hacer.

cHao
fuente
3

Para la pregunta 2 ya veo la solución que sugeriría, por BalusC.

  1. ¿Existe algún escenario de palabras reales cuando la captura de java.lang.OutOfMemoryError puede ser una buena idea?

Creo que acabo de encontrar un buen ejemplo. Cuando la aplicación awt está enviando mensajes, el OutOfMemoryError no detectado se muestra en stderr y se detiene el procesamiento del mensaje actual. ¡Pero la aplicación sigue funcionando! El usuario aún puede emitir otros comandos sin darse cuenta de los graves problemas que ocurren detrás de escena. Especialmente cuando no puede o no observa el error estándar. Entonces, capturar la excepción de oom y proporcionar (o al menos sugerir) el reinicio de la aplicación es algo deseado.

Jarekczek
fuente
3

Solo tengo un escenario en el que detectar un OutOfMemoryError parece tener sentido y parece funcionar.

Escenario: en una aplicación de Android, quiero mostrar varios mapas de bits en la resolución más alta posible y quiero poder hacer zoom con fluidez.

Debido al zoom fluido, quiero tener los mapas de bits en la memoria. Sin embargo, Android tiene limitaciones de memoria que dependen del dispositivo y son difíciles de controlar.

En esta situación, puede haber OutOfMemoryError al leer el mapa de bits. Aquí, ayuda si lo atrapo y luego continúo con una resolución más baja.

Jörg Eisfeld
fuente
0
  1. Depende de cómo se defina "bueno". Hacemos eso en nuestra aplicación web con errores y funciona la mayor parte del tiempo (afortunadamente, ahora OutOfMemoryno sucede debido a una solución no relacionada). Sin embargo, incluso si lo detecta, es posible que se haya roto algún código importante: si tiene varios subprocesos, la asignación de memoria puede fallar en cualquiera de ellos. Entonces, dependiendo de su aplicación, todavía hay un 10-90% de posibilidades de que se rompa de manera irreversible.
  2. Por lo que tengo entendido, el desenrollado de una pila pesada en el camino invalidará tantas referencias y, por lo tanto, liberará tanta memoria que no debería importarle.

EDITAR: Te sugiero que lo pruebes. Digamos, escriba un programa que llame de forma recursiva a una función que asigne progresivamente más memoria. Capture OutOfMemoryErrory vea si puede continuar de manera significativa desde ese punto. Según mi experiencia, podrá hacerlo, aunque en mi caso sucedió en el servidor WebLogic, por lo que podría haber algo de magia negra involucrada.

doble
fuente
-1

Puede capturar cualquier cosa en Throwable, en términos generales, solo debe capturar subclases de Exception excluyendo RuntimeException (aunque una gran parte de los desarrolladores también detecta RuntimeException ... pero esa nunca fue la intención de los diseñadores del lenguaje).

Si pudieras atrapar OutOfMemoryError, ¿qué demonios harías? La máquina virtual no tiene memoria, básicamente todo lo que puede hacer es salir. Probablemente ni siquiera pueda abrir un cuadro de diálogo para decirles que no tiene memoria, ya que eso ocuparía memoria :-)

La máquina virtual arroja un OutOfMemoryError cuando realmente se queda sin memoria (de hecho, todos los errores deberían indicar situaciones irrecuperables) y realmente no debería haber nada que pueda hacer para solucionarlo.

Lo que debe hacer es averiguar por qué se está quedando sin memoria (use un generador de perfiles, como el de NetBeans) y asegurarse de que no tenga pérdidas de memoria. Si no tiene pérdidas de memoria, aumente la memoria que asigna a la máquina virtual.

Tofu cerveza
fuente
7
Un concepto erróneo que perpetúa su publicación es que OOM indica que la JVM no tiene memoria. En cambio, en realidad indica que la JVM no pudo asignar toda la memoria que se le indicó. Es decir, si la JVM tiene 10B de espacio y "nuevo" un objeto de 100B, fallará, pero podría dar la vuelta y "nuevo" un objeto de 5B y estar bien.
Tim Bender
1
Y si solo necesitaba 5B, ¿por qué estoy pidiendo 10B? Si está haciendo la asignación basada en prueba y error, lo está haciendo mal.
TofuBeer
2
Supongo que Tim quiso decir que aún puedes realizar algún trabajo incluso con una situación de OutOfMemory. Podría quedar suficiente memoria para abrir un diálogo, por ejemplo.
Stephen Eilert