2011-01-24 14 views
11

En C++ y C# cuando no se puede asignar suficiente memoria, lanza una excepción.¿Qué pasa si falla el nuevo?

No he podido encontrar ninguna información sobre el comportamiento de los nuevos en Java. Entonces, ¿qué pasará si falla una nueva versión en Java (memoria insuficiente)?

Respuesta

23

Asumiendo que específicamente decir fracaso de la asignación de memoria, entonces debería tirar OutOfMemoryError

inicia cuando la Máquina Virtual de Java no puede asignar un objeto porque no tiene memoria, y no hay más memoria podría ser puesto a disposición por el recolector de basura.

Al igual que todas las subclases de Error, por lo general es una condición no recuperable, aunque técnicamente se puede capturas que:

un error es una subclase de Throwable que indica serios problemas que una razonable la aplicación no debería intentar atrapar. La mayoría de esos errores son condiciones anormales. El error ThreadDeath, aunque es una condición "normal", también es una subclase de Error porque la mayoría de las aplicaciones no deberían intentar atraparlo.

No se requiere un método para declarar en su cláusula throws ninguna subclase de error que pueda lanzarse durante la ejecución del método pero que no se capture, ya que estos errores son condiciones anormales que nunca deberían ocurrir.

+1

Es posible escribir código que se recupere de esta condición, siempre que tenga un buen motivo para detectar un problema conocido. Esto rara vez es una buena idea y, por lo general, la mejor opción es reducir la memoria consumida o aumentar la memoria máxima. –

2

Si realmente no tiene suficiente memoria, se lanza OutOfMemoryError. También cualquier excepción puede ser lanzada por el propio constructor.

1

Puede detectar OutOfMemoryExceptions pero no se recomienda. Sin embargo, a menos que se trate de un problema de codificación/diseño, el recolector de basura debería encargarse de administrar el montón.

Si crees que vas a hacer una gran cantidad de procesamiento de datos y puedes ejecutar la memoria, siempre puedes verificar el espacio libre disponible antes de comenzar la ejecución (copia el fragmento de código de este link).

// Get current size of heap in bytes 
long heapSize = Runtime.getRuntime().totalMemory(); 

// Get maximum size of heap in bytes. The heap cannot grow beyond this size. 
// Any attempt will result in an OutOfMemoryException. 
long heapMaxSize = Runtime.getRuntime().maxMemory(); 

// Get amount of free memory within the heap in bytes. This size will increase 
// after garbage collection and decrease as new objects are created. 
long heapFreeSize = Runtime.getRuntime().freeMemory(); 
+0

OOM no solo se debe a problemas de codificación/diseño, al menos no a los que siempre se puede controlar. Las pérdidas de memoria en las famosas API de terceros, que han sido extremadamente comunes durante la vida de Java (y que seguirán siéndolo), me vienen a la mente ... – SyntaxT3rr0r

+2

La opción segura de API de terceros es parte del diseño en mi opinión. – CoolBeans

4

Cuando Java no puede obtener suficiente memoria para asignar un objeto obtendrá un OutOfMemoryError.

En la práctica, la JVM puede demorar bastante tiempo en ejecutarse. Cuando se enfrenta a un problema de memoria, la JVM primero intentará eliminar la mayor cantidad de memoria posible. Dependiendo de la configuración de JVM (parámetros de GC y memoria de montón máxima), un ciclo de GC puede tomar de varios segundos a varios minutos con Xmx configurado en varios gigabytes. Peor aún, dependiendo de la memoria necesaria, la JVM puede realizar varios ciclos de GC antes de lanzar la excepción.

Cuando se lanza la excepción, se procesa como cualquier excepción no detectada. Como tal, se propagará a la parte superior de la pila de llamadas del hilo donde se produjo la excepción. Como la excepción no está capturada, el subproceso mostrará un stacktrace en System.err antes de morir. Eso es todo. En un programa de subproceso único, esto hará que el programa salga. En un programa de subprocesos múltiples, la muerte de este subproceso puede liberar suficiente memoria para que el programa siga ejecutándose en una configuración inestable.

Mi recomendación si le preocupa el problema de memoria es que debe registrarse y UncaughtExceptionHandler para matar su programa cuando surge un problema de memoria, ya que es mejor detener el programa que dejarlo funcionar en un estado indefinido sin que nadie lo sepa .

Usted puede leer los siguientes artículos de Heinz Kabutz sobre el tema:

2

Un poco más en OOME.

/*License - LGPL 
<h3>Recovery from an OutOfMemory Error</h3> 
<p>The JavaDocs for Error state, in the first sentence.. 

<blockquote>"An Error is a subclass of Throwable that indicates 
serious problems that a reasonable application should 
not try to catch."</blockquote> 

<p>This advice has led to the fallacy that an OutOfMemoryError 
should not be caught and dealt with. But this demo. shows 
that it is quite easy to recover to the point of providing 
the user with meaningful information, and advice on how to 
proceed. 

<p>I aim to make my applications 'unreasonable'. ;-) 
*/ 

import java.awt.event.ActionListener; 
import java.awt.event.ActionEvent; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JPanel; 
import javax.swing.JLabel; 
import javax.swing.JProgressBar; 
import javax.swing.JOptionPane; 
import javax.swing.JDialog; 
import javax.swing.Timer; 

import javax.swing.border.EmptyBorder; 

import java.util.ArrayList; 

/** A demo. showing recovery from an OutOfMemoryError. 
Our options once an OOME is encountered are relatively 
few, but we can still warn the end user and provide 
advice on how to correct the problem. 
@author Andrew Thompson */ 
public class MemoryRecoveryTest { 

    public static void main(String[] args) { 
     // reserve a buffer of memory 
     byte[] buffer = new byte[2^10]; 
     ArrayList<Object> list = new ArrayList<Object>(); 
     final JProgressBar memory = new JProgressBar(
      0, 
      (int)Runtime.getRuntime().totalMemory()); 
     ActionListener listener = new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       memory.setValue(
        (int)Runtime.getRuntime().freeMemory()); 
      } 
     }; 
     Timer timer = new Timer(500, listener); 
     timer.start(); 

     JDialog dialog = new JDialog(); 
     dialog.setTitle("Available Memory"); 
     JPanel memoryPanel = new JPanel(); 
     memoryPanel.add(memory); 
     memoryPanel.setBorder(new EmptyBorder(25,25,25,25)); 
     dialog.add(memoryPanel); 
     dialog.pack(); 
     dialog.setLocationRelativeTo(null); 
     dialog.setVisible(true); 
     dialog.addWindowListener(new WindowAdapter(){ 
      @Override 
      public void windowClosing(WindowEvent we) { 
       System.exit(0); 
      } 
     }); 

     // prepare a memory warning panel in advance 
     JPanel memoryWarning = new JPanel(); 
     memoryWarning.add(new JLabel(
      "<HTML><BODY>There is not enough memory to" + 
      " complete the task!<BR> Use a variant " + 
      " of the application that assigns more memory.")); 

     try { 
      // do our 'memory intensive' task 
      while(true) { 
       list.add(new Object()); 
      } 
     } catch(OutOfMemoryError oome) { 
      // provide the VM with some memory 'breathing space' 
      // by clearing the buffer 
      buffer = null; 
      // tell the user what went wrong, and how to fix it 
      JOptionPane.showMessageDialog(
       dialog, 
       memoryWarning, 
       "Out of Memory!", 
       JOptionPane.ERROR_MESSAGE); 
     } 
    } 
} 
+0

Yo diría que no es una falacia - ver http://stackoverflow.com/a/6213636/139985 –

Cuestiones relacionadas