Catturare java.lang.OutOfMemoryError?


101

Documentazione per java.lang.Errordice:

Un errore è una sottoclasse di Throwable che indica problemi seri che un'applicazione ragionevole non dovrebbe cercare di individuare

Ma poiché java.lang.Errorè una sottoclasse di java.lang.Throwable, posso catturare questo tipo di Lanciabile.

Capisco perché non è una buona idea cogliere questo tipo di eccezione. Per quanto ho capito, se decidiamo di catturarlo, il gestore di cattura non dovrebbe allocare alcuna memoria da solo. Altrimenti OutOfMemoryErrorverrà lanciato di nuovo.

Quindi, la mia domanda è:

  1. Ci sono scenari del mondo reale in cui la cattura java.lang.OutOfMemoryErrorpotrebbe essere una buona idea?
  2. Se decidiamo di catturare java.lang.OutOfMemoryError, come possiamo assicurarci che il gestore di cattura non allochi memoria da solo (strumenti o best practice)?


Per la tua prima domanda, aggiungerò che prenderò OutOfMemoryError per (almeno provare a) avvisare l'utente del problema. In precedenza, l'errore non veniva rilevato dalla clausola catch (Exception e) e all'utente non veniva mostrato alcun feedback.
Josep Rodríguez López

1
Ci sono casi specifici, ad esempio, l'allocazione di un array gigantesco, in cui è possibile rilevare l'errore OOM attorno a tale operazione e recuperare ragionevolmente bene. Ma posizionare il try / catch attorno a una grande quantità di codice e tentare di ripristinare in modo pulito e continuare è probabilmente una cattiva idea.
Hot Licks

Risposte:


85

Sono d'accordo e non sono d'accordo con la maggior parte delle risposte qui.

Ci sono una serie di scenari in cui potresti voler catturare una OutOfMemoryErrore, nella mia esperienza (su Windows e Solaris JVM), solo molto raramente è OutOfMemoryErrorla campana a morto per una JVM.

C'è solo una buona ragione per catturare un OutOfMemoryErrored è chiudere con garbo, rilasciando in modo pulito le risorse e registrando il motivo dell'errore meglio che puoi (se è ancora possibile farlo).

In generale, si OutOfMemoryErrorverifica a causa di un'allocazione di memoria a blocchi che non può essere soddisfatta con le risorse rimanenti dell'heap.

Quando Errorviene lanciato, l'heap contiene la stessa quantità di oggetti allocati come prima dell'allocazione non riuscita e ora è il momento di eliminare i riferimenti agli oggetti di runtime per liberare ancora più memoria che potrebbe essere necessaria per la pulizia. In questi casi, potrebbe anche essere possibile continuare, ma sarebbe sicuramente una cattiva idea poiché non si può mai essere certi al 100% che la JVM sia in uno stato riparabile.

Dimostrazione che OutOfMemoryErrornon significa che la JVM abbia esaurito la memoria nel blocco catch:

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");
        }
    }
}

Output di questo codice:

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

Se Erroreseguo qualcosa di critico, di solito prendo il , lo registro su syserr, quindi lo registro usando il mio framework di registrazione preferito, quindi procedo al rilascio delle risorse e chiudo in modo pulito. Qual è la cosa peggiore che può succedere? La JVM sta morendo (o è già morta) in ogni caso e catturando Errorc'è almeno una possibilità di pulizia.

L'avvertenza è che devi mirare alla cattura di questi tipi di errori solo nei luoghi in cui è possibile la pulizia. Non coprire catch(Throwable t) {}ovunque o sciocchezze del genere.


D'accordo, posterò il mio esperimento su una nuova risposta.
Mister Smith

4
"non puoi mai essere certo al 100% che la JVM sia in uno stato riparabile": perché OutOfMemoryErrorpotrebbe essere stato lanciato da un punto che ha posto il tuo programma in uno stato incoerente, perché può essere lanciato in qualsiasi momento. Vedi stackoverflow.com/questions/8728866/…
Raedwald

In OpenJdk1.7.0_40, non ottengo alcun errore o eccezione quando eseguo questo codice. Anche io ho cambiato MEGABYTE in GIGABYTE (1024 * 1024 * 1024). È perché l'ottimizzatore rimuove la variabile "byte [] byte" poiché non viene utilizzata nel resto del codice?
RoboAlex

"Ci sono una serie di scenari in cui potresti voler catturare un OutOfMemoryError" rispetto a "C'è solo una buona ragione per catturare un OutOfMemoryError" . Prendi una decisione !!!
Stephen C

3
Scenario del mondo reale in cui POTREBBE voler rilevare l'errore OutOfMemory: quando è causato dal tentativo di allocare un array con più di 2G elementi. Il nome dell'errore è un po 'improprio in questo caso, ma è ancora un OOM.
Charles Roth,

31

È possibile recuperare da esso:

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;
            }
        }
    }

}

Ma ha senso? Cos'altro vorresti fare? Perché inizialmente dovresti allocare così tanta memoria? Va bene anche meno memoria? Perché non lo usi già comunque? O se ciò non è possibile, perché non dare alla JVM più memoria dall'inizio?

Torna alle tue domande:

1: ci sono scenari di parole reali quando si cattura java.lang.OutOfMemoryError potrebbe essere una buona idea?

Nessuno mi viene in mente.

2: se catturiamo java.lang.OutOfMemoryError come possiamo essere sicuri che il gestore catch non allochi memoria da solo (strumenti o best practice)?

Dipende da cosa ha causato l'OOME. Se è dichiarato fuori dal tryblocco ed è successo passo dopo passo, le tue possibilità sono poche. Si potrebbe voler riservare dello spazio di memoria in anticipo:

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

e quindi impostarlo a zero durante OOME:

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

Ovviamente tutto questo non ha senso;) Basta dare a JVM memoria sufficiente come richiesto dalla tua applicazione. Se necessario, esegui un profiler.


1
Anche riservare lo spazio non garantisce però una soluzione funzionante. Quello spazio potrebbe essere preso anche da qualche altro thread;)
Wolph

@ Wolph: Allora dai alla JVM più memoria! O_o Tutto sommato non ha davvero senso;)
BalusC

2
Il primo frammento funziona perché l'oggetto che ha attivato l'errore è un singolo oggetto BIG (l'array). Quando viene raggiunta la clausola catch, è stata raccolta dalla JVM affamata di memoria. Se stavi usando lo stesso oggetto al di fuori del blocco try, o in un altro thread, o nella stessa cattura, JVM non lo raccoglie, rendendo impossibile creare un nuovo oggetto singolo di qualsiasi tipo. il secondo frammento, ad esempio, potrebbe non funzionare.
Mister Smith,

3
perché non impostarlo semplicemente su null?
Pacerier

1
@MisterSmith Il tuo commento non ha senso. Il grande oggetto non esiste. Non è stato allocato in primo luogo: ha attivato l'OOM, quindi di certo non ha bisogno di GC.
Marchese di Lorne

16

In generale, è una cattiva idea provare a catturare e recuperare da un OOM.

  1. Un OOME potrebbe anche essere stato lanciato su altri thread, inclusi thread di cui l'applicazione non è nemmeno a conoscenza. Tutti i thread di questo tipo saranno ora morti e tutto ciò che era in attesa di una notifica potrebbe essere bloccato per sempre. In breve, la tua app potrebbe essere interrotta in modo terminale.

  2. Anche se ripristini correttamente, la tua JVM potrebbe ancora soffrire di fame di heap e la tua applicazione funzionerà in modo abissale di conseguenza.

La cosa migliore da fare con un OOME è lasciare morire la JVM.

(Questo presuppone che la JVM fa morire. Per esempio Ooms su un filo servlet Tomcat non uccidere la JVM, e questo porta alla Tomcat andare in uno stato catatonico in cui non risponderà a tutte le richieste ... non richiede nemmeno a ricomincia.)

MODIFICARE

Non sto dicendo che sia una cattiva idea catturare OOM. I problemi sorgono quando poi si tenta di riprendersi dall'OOME, deliberatamente o per svista. Ogni volta che si cattura un OOM (direttamente o come sottotipo di Error o Throwable) è necessario rilanciarlo o fare in modo che l'applicazione / JVM esca.

A parte: questo suggerisce che per la massima robustezza di fronte agli OOM, un'applicazione dovrebbe utilizzare Thread.setDefaultUncaughtExceptionHandler () per impostare un gestore che causerà l'uscita dell'applicazione in caso di OOME, indipendentemente dal thread su cui viene lanciato OOME. Sarei interessato a opinioni su questo ...

L'unico altro scenario è quando sai per certo che l'OOM non ha provocato alcun danno collaterale; cioè tu sai:

  • cosa ha causato specificamente l'OOME,
  • cosa stava facendo l'applicazione in quel momento, e che è OK semplicemente scartare quel calcolo, e
  • che un OOME (approssimativamente) simultaneo non può essersi verificato su un altro thread.

Esistono applicazioni in cui è possibile conoscere queste cose, ma per la maggior parte delle applicazioni non è possibile sapere con certezza che la continuazione dopo un OOME sia sicura. Anche se empiricamente "funziona" quando lo provi.

(Il problema è che è necessaria una prova formale per dimostrare che le conseguenze delle OOME "anticipate" sono sicure e che le OOME "impreviste" non possono verificarsi sotto il controllo di una prova / cattura OOME.)


Si sono d'accordo con te. In generale, è una cattiva idea. Ma perché allora ho la possibilità di prenderlo? :)
Denis Bazhenov

@dotsid - 1) perché ci sono casi in cui dovresti catturarlo e 2) perché rendere impossibile catturare OOM avrebbe un impatto negativo sul linguaggio e / o su altre parti del runtime Java.
Stephen C

1
Dici: "perché ci sono casi in cui dovresti prenderlo". Quindi questa era parte della mia domanda iniziale. Quali sono i casi in cui vuoi catturare OOME?
Denis Bazhenov

1
@dotsid - vedi la mia risposta modificata. L'unico caso che mi viene in mente per catturare OOM è quando è necessario farlo per forzare l' uscita di un'applicazione multi-thread in caso di OOM. Forse vuoi farlo per tutti i sottotipi di Error.
Stephen C

1
Non si tratta solo di catturare gli OOME. Devi anche riprenderti da loro. Come si ripristina un thread se doveva (dire) notificare un altro thread ... ma ha ottenuto un OOME? Certo, la JVM non morirà. Ma è probabile che l'applicazione smetta di funzionare a causa di thread bloccati in attesa di notifiche da thread che si sono riavviati a causa della cattura di un OOME.
Stephen C

14

Sì, ci sono scenari del mondo reale. Ecco il mio: ho bisogno di elaborare set di dati di moltissimi elementi su un cluster con memoria limitata per nodo. Una data istanza di JVM passa attraverso molti elementi uno dopo l'altro, ma alcuni di essi sono troppo grandi per essere elaborati nel cluster: posso catturare OutOfMemoryErrore prendere nota di quali elementi sono troppo grandi. Successivamente, posso rieseguire solo gli elementi di grandi dimensioni su un computer con più RAM.

(Poiché si tratta di una singola allocazione multi-gigabyte di un array che non riesce, la JVM funziona ancora dopo aver rilevato l'errore e c'è abbastanza memoria per elaborare gli altri elementi.)


Quindi hai un codice come byte[] bytes = new byte[length]? Perché non controllare sizein un punto precedente?
Raedwald

1
Perché lo stesso sizeandrà bene con più memoria. Vado attraverso l'eccezione perché nella maggior parte dei casi andrà tutto bene.
Michael Kuhn

10

Ci sono sicuramente scenari in cui ha senso catturare un OOME. IDEA li rileva e fa apparire una finestra di dialogo che ti consente di modificare le impostazioni della memoria di avvio (e poi esce quando hai finito). Un server delle applicazioni potrebbe rilevarli e segnalarli. La chiave per farlo è farlo ad alto livello durante l'invio in modo da avere una ragionevole possibilità di avere un mucchio di risorse liberate nel punto in cui stai catturando l'eccezione.

Oltre allo scenario IDEA sopra, in generale la cattura dovrebbe essere di Throwable, non solo OOM in particolare, e dovrebbe essere eseguita in un contesto in cui almeno il thread verrà terminato a breve.

Ovviamente la maggior parte delle volte la memoria muore di fame e la situazione non è recuperabile, ma ci sono modi in cui ha senso.


8

Mi sono imbattuto in questa domanda perché mi chiedevo se sia una buona idea catturare OutOfMemoryError nel mio caso. Sto rispondendo qui in parte per mostrare ancora un altro esempio quando rilevare questo errore può avere senso per qualcuno (cioè me) e in parte per scoprire se è davvero una buona idea nel mio caso (essendo uno sviluppatore uber junior non posso mai essere troppo sicuro di ogni singola riga di codice che scrivo).

Ad ogni modo, sto lavorando su un'applicazione Android che può essere eseguita su diversi dispositivi con diverse dimensioni di memoria. La parte pericolosa è decodificare una bitmap da un file e visualizzarla in un'istanza ImageView. Non voglio limitare i dispositivi più potenti in termini di dimensioni della bitmap decodificata, né posso essere sicuro che l'app non verrà eseguita su un dispositivo antico che non ho mai incontrato con memoria molto bassa. Quindi faccio questo:

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;
  }
}

In questo modo riesco a fornire dispositivi sempre meno potenti in base alle loro esigenze e aspettative, o meglio dei loro utenti.


1
Un'altra opzione sarebbe calcolare quanto sono grandi le bitmap che puoi gestire invece di provare e fallire. "Le eccezioni dovrebbero essere utilizzate per casi eccezionali" - Penso che qualcuno abbia detto. Ma dirò che la tua soluzione sembra la via d'uscita più semplice, forse non la migliore, ma probabilmente la più semplice.
jontejj

Dipende dal codec. Immagina che un bmp di 10 MB risulti probabilmente in poco più di 10 MB di heap, mentre un JPEG di 10 MB "esploderà". Lo stesso nel mio caso in cui voglio analizzare un XML che può variare notevolmente a seconda della complessità del contenuto
Daniel Alder

5

Sì, la vera domanda è "cosa intendi fare nel gestore delle eccezioni?" Per quasi tutto ciò che è utile, assegnerai più memoria. Se desideri eseguire un lavoro diagnostico quando si verifica un'eccezione OutOfMemoryError, puoi utilizzare l' -XX:OnOutOfMemoryError=<cmd>hook fornito dalla VM HotSpot. Eseguirà i tuoi comandi quando si verifica un'eccezione OutOfMemoryError e puoi fare qualcosa di utile al di fuori dell'heap di Java. Vuoi davvero impedire all'applicazione di esaurire la memoria in primo luogo, quindi capire perché accade è il primo passo. Quindi è possibile aumentare la dimensione dell'heap di MaxPermSize come appropriato. Ecco alcuni altri utili hook HotSpot:

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

Vedi l'elenco completo qui


È anche peggio di quanto pensi. Poiché un OutOfMemeoryError può essere lanciato in qualsiasi punto del tuo programma (non solo da newun'istruzione), il tuo programma sarà in uno stato indefinito quando catturi l'eccitazione.
Raedwald

5

Ho un'applicazione che deve essere ripristinata da errori OutOfMemoryError e nei programmi a thread singolo funziona sempre, ma a volte non nei programmi multi-thread. L'applicazione è uno strumento di test Java automatizzato che esegue le sequenze di test generate con la massima profondità possibile sulle classi di test. Ora, l'interfaccia utente deve essere stabile, ma il motore di test può esaurire la memoria durante la crescita dell'albero dei casi di test. Lo gestisco con il seguente tipo di linguaggio del codice nel motore di prova:

booleano isOutOfMemory = false; // flag utilizzato per la segnalazione
provare {
   SomeType largeVar;
   // Loop principale che alloca sempre di più a largeVar
   // può terminare OK o sollevare OutOfMemoryError
}
catch (OutOfMemoryError ex) {
   // largeVar è ora fuori dall'ambito, quindi è spazzatura
   System.gc (); // ripulisce i dati largeVar
   isOutOfMemory = true; // flag disponibile per l'uso
}
// programma verifica flag per segnalare il ripristino

Funziona ogni volta nelle applicazioni a thread singolo. Ma di recente ho inserito il mio motore di test in un thread di lavoro separato dall'interfaccia utente. Ora, la memoria esaurita può verificarsi arbitrariamente in entrambi i thread e non mi è chiaro come rilevarla.

Ad esempio, ho avuto OOME mentre i fotogrammi di una GIF animata nella mia interfaccia utente venivano ciclati da un thread proprietario creato dietro le quinte da una classe Swing che è fuori dal mio controllo. Pensavo di aver allocato in anticipo tutte le risorse necessarie, ma chiaramente l'animatore alloca memoria ogni volta che recupera l'immagine successiva. Se qualcuno ha un'idea su come gestire gli OOME sollevati in qualsiasi thread, mi piacerebbe sentire.


In una singola app a thread, se non stai più utilizzando alcuni dei nuovi oggetti problematici la cui creazione ha generato l'errore, questi possono essere raccolti nella clausola catch. Tuttavia, se la JVM rileva che l'oggetto può essere utilizzato in seguito, non può essere raccolto e l'app esplode. Vedi la mia risposta in questo thread.
Mister Smith

4

OOME può essere catturato ma sarà generalmente inutile, a seconda se la JVM è in grado di raccogliere alcuni oggetti quando viene raggiunto il punto di cattura e quanta memoria heap è rimasta in quel momento.

Esempio: nella mia JVM, questo programma viene eseguito fino al completamento:

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");
    }  
}

Tuttavia, solo aggiungendo una singola linea sul fermo ti mostrerà di cosa sto parlando:

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");
    }
}

Il primo programma funziona bene perché quando viene raggiunto il catch, la JVM rileva che l'elenco non verrà più utilizzato (questo rilevamento può essere anche un'ottimizzazione effettuata in fase di compilazione). Quindi, quando raggiungiamo l'istruzione print, la memoria heap è stata liberata quasi completamente, quindi ora abbiamo un ampio margine di manovra per continuare. Questo è il caso migliore.

Tuttavia, se il codice è organizzato in modo che l'elenco llvenga utilizzato dopo che OOME è stato rilevato, la JVM non è in grado di raccoglierlo. Questo accade nel secondo snippet. L'OOME, attivato da una nuova creazione Long, viene catturato, ma presto stiamo creando un nuovo Object (una stringa nella System.out,printlnlinea) e l'heap è quasi pieno, quindi viene lanciato un nuovo OOME. Questo è lo scenario peggiore: abbiamo provato a creare un nuovo oggetto, abbiamo fallito, abbiamo catturato OOME, sì, ma ora la prima istruzione che richiede una nuova memoria heap (ad esempio: creazione di un nuovo oggetto) lancerà un nuovo OOME. Pensaci, cos'altro possiamo fare a questo punto con così poca memoria rimasta ?. Probabilmente sto solo uscendo. Da qui l'inutile.

Tra le ragioni per cui la JVM non raccoglie risorse, una fa davvero paura: una risorsa condivisa con altri thread che ne fanno uso. Chiunque abbia un cervello può vedere quanto può essere pericoloso catturare OOME se inserito su qualche app non sperimentale di qualsiasi tipo.

Sto usando una JVM di Windows x86 a 32 bit (JRE6). La memoria predefinita per ogni app Java è 64 MB.


E se facessi ll=nullall'interno del blocco di cattura?
Naanavanalla

3

L'unico motivo per cui riesco a pensare al motivo per cui rilevare errori OOM potrebbe essere che hai alcune enormi strutture di dati che non stai più utilizzando e che puoi impostare su null e liberare memoria. Ma (1) questo significa che stai sprecando memoria e dovresti correggere il tuo codice piuttosto che zoppicare dopo un OOME, e (2) anche se lo prendessi, cosa faresti? OOM può accadere in qualsiasi momento, lasciando potenzialmente tutto a metà.


3

Per la domanda 2 vedo già la soluzione che suggerirei, di BalusC.

  1. Ci sono scenari di parole reali quando catturare java.lang.OutOfMemoryError potrebbe essere una buona idea?

Penso di aver appena trovato un buon esempio. Quando l'applicazione awt invia messaggi, OutOfMemoryError non registrato viene visualizzato su stderr e l'elaborazione del messaggio corrente viene interrotta. Ma l'applicazione continua a funzionare! L'utente può comunque emettere altri comandi ignaro dei gravi problemi che si verificano dietro le quinte. Soprattutto quando non può o non osserva l'errore standard. Quindi catturare un'eccezione e fornire (o almeno suggerire) il riavvio dell'applicazione è qualcosa di desiderato.


3

Ho solo uno scenario in cui la cattura di un OutOfMemoryError sembra avere senso e sembra funzionare.

Scenario: in un'app Android, voglio visualizzare più bitmap con la massima risoluzione possibile e voglio essere in grado di ingrandirle in modo fluido.

A causa dello zoom fluido, desidero avere le bitmap in memoria. Tuttavia, Android ha limitazioni nella memoria che dipendono dal dispositivo e che sono difficili da controllare.

In questa situazione, potrebbe essere presente OutOfMemoryError durante la lettura della bitmap. Qui, aiuta se lo prendo e poi continuo con una risoluzione inferiore.


0
  1. Dipende da come definisci "buono". Lo facciamo nella nostra applicazione web difettosa e funziona per la maggior parte del tempo (per fortuna, oraOutOfMemory non accade a causa di una correzione non correlata). Tuttavia, anche se lo prendi, potrebbe comunque aver rotto un codice importante: se hai diversi thread, l'allocazione della memoria può fallire in ognuno di essi. Quindi, a seconda dell'applicazione, c'è ancora il 10-90% di possibilità che si rompa irreversibilmente.
  2. Per quanto ho capito, lo svolgimento di uno stack pesante durante il percorso invaliderà così tanti riferimenti e quindi libererà così tanta memoria che non dovresti preoccuparti di questo.

EDIT: ti suggerisco di provarlo. Diciamo, scrivi un programma che richiami in modo ricorsivo una funzione che alloca progressivamente più memoria. Prendi OutOfMemoryErrore vedi se puoi continuare in modo significativo da quel punto. Secondo la mia esperienza, sarai in grado di farlo, anche se nel mio caso è successo sotto il server WebLogic, quindi potrebbe esserci stata qualche magia nera coinvolta.


-1

Puoi catturare qualsiasi cosa sotto Throwable, in generale dovresti catturare solo sottoclassi di Exception escludendo RuntimeException (sebbene una gran parte degli sviluppatori catturi anche RuntimeException ... ma non è mai stato l'intento dei progettisti del linguaggio).

Se dovessi catturare OutOfMemoryError cosa diavolo faresti? La VM ha esaurito la memoria, in pratica tutto ciò che puoi fare è uscire. Probabilmente non puoi nemmeno aprire una finestra di dialogo per dire loro che hai esaurito la memoria poiché ciò richiederebbe memoria :-)

La VM lancia un'eccezione OutOfMemoryError quando la memoria è veramente esaurita (infatti tutti gli errori dovrebbero indicare situazioni irrecuperabili) e non dovrebbe esserci davvero nulla che tu possa fare per affrontarlo.

Le cose da fare sono scoprire perché stai esaurendo la memoria (usa un profiler, come quello in NetBeans) e assicurati di non avere perdite di memoria. Se non si verificano perdite di memoria, aumentare la memoria allocata alla VM.


7
Un'idea sbagliata che il tuo post perpetua è che OOM indichi che la JVM ha esaurito la memoria. Invece, indica effettivamente che la JVM non è stata in grado di allocare tutta la memoria a cui era stata istruita. Cioè, se la JVM ha 10B di spazio e si "sostituisce" un oggetto da 100B, fallirà, ma si potrebbe girare e "rinnovare" un oggetto da 5B e stare bene.
Tim Bender

1
E se avessi bisogno solo di 5B, perché sto chiedendo 10B? Se stai facendo l'allocazione basata su tentativi ed errori, stai sbagliando.
TofuBeer

2
Immagino che Tim volesse dire che potresti ancora eseguire un po 'di lavoro anche con una situazione OutOfMemory. Ad esempio, potrebbe esserci abbastanza memoria per aprire una finestra di dialogo.
Stephen Eilert
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.