2009-11-07 24 views

Respuesta

78

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

Usted puede captura, ya 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és haciendo algunas cosas bastante específica (la asignación de un montón de cosas dentro de una sección de código específica, por ejemplo) es probable que no puedas atraparlo ya que no sabrás de dónde será arrojado.

+14

Además, es probable que haya ninguna manera fácil para que usted pueda recuperar de ella si lo atrapas. –

+0

@matt b: en el caso específico en el que ** puedas ** atraparlo, presumiblemente estás tratando de controlar el consumo de tu memoria y, por lo tanto, podrías liberar parte o la totalidad. Pero en general tienes razón, por supuesto. – ChssPly76

+0

@ ChssPly76 (y otros): lea mi respuesta para comprender por qué tratar de administrar el consumo de memoria atrapando OOME sería una ** IDEA MALA **. –

1

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 pila unos pocos marcos hará eso por ti, algunas veces necesitas hacer algo más explícito.

+1

Su plan deberá incluir una estrategia para enfrentar la posibilidad de que su programa esté en un estado inconsistente; ver http://stackoverflow.com/questions/8728866/no-throw-virtualmachineerror-guarantees – Raedwald

48

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 
} 
+10

allí * * es al menos una cosa razonable, que podría estar haciendo lo que provoca un OOME y es recuperable: Cargar una imagen muy grande. Lo único en el bloque de prueba es una llamada a ImageIO.read(), y le muestra al usuario un cuadro de diálogo que le dice que la imagen es demasiado grande en el bloque catch. Solo digo ... – uckelman

+1

@uckelman Ese es un enfoque equivocado, a menos que su aplicación sea de un solo hilo. Lo que pasa es que a pesar de su imagen de carga-hilo atrapa OOME, pero los otros hilos no saben acerca de esto y pueden obtener un OOME demasiado –

+4

@SurajChandran: El OOME causado por intentar cargar una imagen muy grande se deberá intentar asigna un 'byte []' o 'int []' muy grande. Obtienes un OOME de eso porque la asignación falla, no porque en realidad estás fuera de memoria, por lo tanto, no causará problemas en otros hilos. – uckelman

1

Es posible coger Cualquier excepción. Sólo tiene que escribir

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

Lo ideal sería que no se supone que coger java.lang.Error excepciones. 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.

2

Es posible, pero si se queda 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 te quedas 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.

24

Puedes coger y tratar de recuperarse de OutOfMemoryError (OOM) excepciones, pero es probablemente una mala idea ... especialmente si su objetivo es que la aplicación a "seguir adelante".

Hay varias razones para esto:

  1. Como otros han señalado, hay mejores formas de gestionar los recursos de memoria que liberar de forma explícita las cosas; 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 es no tratar de seguir adelante a partir de un OOM ... a menos que usted sabe :

  • dónde y por qué sucedió el OOM,
  • que no tienen ha habido algún "daño colateral" y
  • que su recuperación liberará suficiente memoria para continuar.
13

simplemente tirando 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 recopilar 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 objetivo es usar un montón Java de 256 m). ¿entonces qué hago?

creé versiones respaldadas por disco de LinkedLists, Hashtables, etc. estos 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 un montón de razones por las que podría quedarse sin memoria en una aplicación de java - la raíz de la mayoría de estas razones es ya sea uno o ambos: 1. aplicación se ejecuta en una máquina de recursos limitados (o intentos de limitar los recursos uso limitando el tamaño del montón) 2. La aplicación simplemente requiere grandes cantidades de memoria (se sugirió la edición de imágenes, ¿qué tal audio y video? ¿Qué tal los compiladores en mi caso? ¿Qué hay de los recopiladores de datos a largo plazo sin almacenamiento no volátil?)

bits

+0

+1 para una solución interesante. – sleske

7

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

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

+2

"no hay forma de obtener un comportamiento definido": porque 'OutOfMemoryError' se puede lanzar a cualquier parte, incluso en lugares que podrían dejar su programa en un estado incoherente. Consulte http://stackoverflow.com/questions/8728866/no-throw-virtualmachineerror-guarantees – Raedwald

2

Es probable que haya al menos un buen momento para ponerse un OutOfMemoryError, cuando se están 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); 
    } 
    ... 
} 
+0

¿Este código funciona de manera confiable? Tengo exactamente este caso, pero realmente no quiero que se cuelgue la aplicación. Supongo que la alternativa es si (len> someConservativeSize) lanza una nueva IOException ("demasiado larga"); – Quantum7

+3

Este enfoque funciona bien en C++, pero sospecho que no tan bien en Java, porque la conexión entre 'new' y' OutOfMemoryError' es indirecta. Si la asignación solo cabe en la memoria, podría haber un misterioso 'OutOfMemoryError' algún tiempo después. – Raedwald

Cuestiones relacionadas