2011-01-24 37 views
11

In C++ e C# quando nuovo non è in grado di allocare memoria sufficiente, genera un'eccezione.Cosa succede se nuovo fallisce?

Non sono riuscito a trovare alcuna informazione sul comportamento di new in Java. Quindi cosa succederà se nuovi errori in Java (memoria insufficiente)?

risposta

23

Supponendo che si specificamente dire fallimento della allocazione della memoria, allora dovrebbe buttare OutOfMemoryError

generata quando la Java Virtual Machine non può assegnare un oggetto perché è fuori della memoria, e non più di memoria potrebbe essere messo a disposizione dal netturbino.

Come tutte le sottoclassi di Error, di solito è una condizione irreversibile, anche se tecnicamente si possibile cattura è:

Un errore è una sottoclasse di Throwable che indica gravi problemi che una ragionevole l'applicazione non dovrebbe cercare di catturare. La maggior parte di tali errori sono condizioni anormali. L'errore ThreadDeath, sebbene sia una condizione "normale", è anche una sottoclasse di Errore perché la maggior parte delle applicazioni non dovrebbe tentare di catturarla.

Un metodo non è necessario per dichiarare nella sua clausola di derivazione qualsiasi sottoclasse di Errore che potrebbe essere generata durante l'esecuzione del metodo ma non rilevata, poiché questi errori sono condizioni anomale che non dovrebbero mai verificarsi.

+1

È possibile scrivere codice che recupera da questa condizione, purché si abbia un buon motivo per rilevarlo per un problema noto. Raramente è una buona idea e ridurre la memoria consumata o aumentare la memoria massima è solitamente l'opzione migliore. –

2

Se non si dispone di memoria sufficiente OutOfMemoryError viene generato. Anche eventuali eccezioni possono essere lanciate dal costruttore stesso.

1

È possibile prendere OutOfMemoryExceptions ma non consigliato. Tuttavia, a meno che non si tratti di un problema di codifica/progettazione, il garbage collector deve occuparsi della gestione dell'heap.

Se si pensa che si sta eseguendo una grande quantità di elaborazione dei dati e si può eseguire memoria, è sempre possibile verificare lo spazio disponibile prima di iniziare l'esecuzione (copiato lo snippet di codice da questo 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 non sono solo dovuti a problemi di codifica/progettazione, almeno non a quelli che puoi sempre controllare. Perdite di memoria in API di terze parti famose, che sono state estremamente comuni durante la vita di Java (e che sicuramente continueranno ad esserlo), mi vengono in mente ... – SyntaxT3rr0r

+2

La scelta di API di terze parti fa parte del design a mio parere. – CoolBeans

4

Quando Java non può ottenere abbastanza memoria da allocare un oggetto si otterrà un OutOfMemoryError.

In pratica l'eccezione può richiedere del tempo per essere effettivamente lanciata dalla JVM. Di fronte al problema della memoria, la JVM prima tenterà di spazzare più memoria possibile. A seconda della configurazione JVM (parametri GC e memoria heap massima), un ciclo GC può richiedere da alcuni secondi a diversi minuti con Xmx impostato su diversi gigabyte. Ancora peggio, a seconda della memoria necessaria, la JVM può eseguire diversi cicli GC prima di lanciare l'eccezione.

Quando l'eccezione è lanciata, viene elaborata come qualsiasi eccezione non rilevata. Come tale si propagherà all'inizio dello stack chiamante del thread in cui è stata sollevata l'eccezione. Poiché l'eccezione non viene visualizzata, il thread mostrerà uno stacktrace su System.err prima di morire. È tutto. In un programma a thread singolo questo farà uscire il programma. In un programma multi-thread, questo thread death può liberare abbastanza memoria affinché il programma continui a girare in una configurazione instabile.

La mia raccomandazione se sei preoccupato per il problema di memoria è che dovresti registrarti e UncaughtExceptionHandler per uccidere il tuo programma quando sorge un problema di memoria dato che è sicuramente meglio interrompere il tuo programma piuttosto che farlo funzionare in uno stato indefinito senza che nessuno sappia .

è possibile leggere le seguenti articoli da Heinz Kabutz sul tema:

2

Un po 'più su 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

Direi che non è un errore - vedi http://stackoverflow.com/a/6213636/139985 –

Problemi correlati