2013-08-10 10 views
5

Ho bisogno di comprensione da voi espertiPerché comportamenti diversi per OOME mentre si tenta di catturarlo?

Questo programma non va a prendere a blocchi (come Heap è pieno, ma voglio capire perché)

public class OOME_NotCatch { 

    static List l = new ArrayList(); 
    static Long i = new Long(1); 

    public static void main(String[] args) { 
     try { 
      while (true) { 
       l.add(i); 
       i++; 
      } 
     } catch (OutOfMemoryError e) { 
      e.printStackTrace(); 
      System.out.println("Encountered OutOfMemoryError"); 
     } 
    } 
} 
//Console : Exception in thread "main" 

Ma il sotto programma viene eseguito bene, anche dopo ottenendo OOME:

public class Catch_OOME_Collection { 

    static List l = new ArrayList(); 

    public static void main(String[] args) { 
     try { 
      while (true) { 
       l.add(new byte[1000000]); 
       System.out.println("size " + l.size()); 
      } 
     } catch (OutOfMemoryError e) { 
      System.out.println("Encountered OutOfMemoryError"); 
      e.printStackTrace(); 
      System.out.println("size of list is " + l.size()); 
      Iterator i = l.iterator(); 
      while(i.hasNext()){ 
       System.out.println(i.next().toString()); 
       i.remove(); 
      } 
      while (true) { 
       System.out.println("keep printing"); 
      } 
     } 
    } 
} 

sto po 'confuso, dopo aver visto i risultati diversi per lo stesso OOME errore. Please guide

risposta

8

La mia comprensione è che, nel primo programma, l'OOME viene lanciato quando si tenta di allocare un nuovo oggetto Long, che richiede solo pochi byte di memoria. Ciò significa che l'heap è completamente pieno e che non è più disponibile memoria per eseguire il blocco catch.

Nel secondo programma, l'OOME viene generato quando si tenta di allocare una nuova matrice di 1 milione di byte. Fallisce, ma ciò può significare che l'heap ha ancora 999.990 byte disponibili, il che è sufficiente per consentire l'esecuzione del blocco catch.

+0

Non capisco l'analisi del primo programma. Oltre a ciò, il gestore delle eccezioni gira per me, come potrebbe la JVM essere in grado di avviarsi in uno stato che non gli consentirebbe di allocare sostanzialmente alcuna memoria? Trovo più probabile che la JVM stia spegnendo prima di sysout flush, e l'utilizzo di syserr potrebbe produrre un risultato diverso per l'OP. –

+0

La JVM deve allocare memoria per eseguire le istruzioni nel blocco catch, (stampare la traccia dello stack, ecc.) E non ne ha. Quindi esce la JVM. In breve, la mia risposta è simile alla risposta di Joni, ma più focalizzata sul perché il secondo programma lascia la JVM con memoria disponibile mentre il primo non lo fa. –

+0

Ok, ma cosa c'entra questo con l'allocazione di un nuovo 'Long'? –

5

Entrambi i programmi immettono il blocco catch. Quello che succede è che uno di loro può esaurire la memoria prima che riesca a generare e stampare un messaggio, e il programma riceve subito un nuovo OutOfMemoryError.

Quando provo il primo programma, vedo l'output generato dal blocco catch, che mostra l'esecuzione del programma imprevedibile una volta che viene generato un errore. Nella traccia dello stack vedo che OOME è stato lanciato durante il tentativo di creare un nuovo array di supporto per lo ArrayList, il che significa che c'era ancora abbastanza memoria per eseguire il blocco catch. Se l'OOME è stato lanciato mentre si creava l'oggetto più piccolo Long, le cose potrebbero essere diverse.

Ciò che è importante notare è che non è possibile catturare uno OutOfMemoryError in modo significativo: l'errore può essere generato in un luogo molto scomodo, lasciando strutture di dati interne in stati incoerenti. In questo caso non ci sono effetti negativi visibili, ma se hai analizzato i campi interni di ArrayList, troverai che il suo campo modCount è stato incrementato senza che l'elenco sia stato effettivamente modificato.

+0

Non sono sicuro di capire cosa intendi. Quando viene rilevata l'eccezione, non ha nemmeno abbastanza memoria da stampare? –

+0

Il metodo 'e.printStackTrace()' potrebbe dover creare molte stringhe e altri oggetti per stampare il messaggio. Quando il programma è in esecuzione con poca memoria, anche la creazione di un solo oggetto aggiuntivo può causare un altro OOME. – Joni

+0

Quindi, quando viene lanciata questa eccezione, cosa può effettivamente fare il programma? –

0

Il primo programma esaurisce la memoria durante l'allocazione di uno Long o più probabilmente aumentando la dimensione dell'array interno.

Il secondo programma quasi certamente esaurisce la memoria durante l'allocazione di un byte[1000000]. Questa è probabilmente una quantità molto maggiore di memoria rispetto la causa del fallimento del primo programma, in modo che la memoria esistente è probabilmente in nessun posto vicino esaurito come nel primo caso, quindi il codice nel blocco catch può riuscire ad assegnare alcuni Strings ecc. per fare ciò che deve fare.

Problemi correlati