Va * mai * bene catturare StackOverflowError in Java?


27

Pensavo che non lo fosse, ma ieri dovevo farlo. È un'applicazione che utilizza Akka (un'implementazione del sistema attore per la JVM) per elaborare lavori asincroni. Uno degli attori esegue alcune manipolazioni di PDF e poiché la libreria è difettosa, muore di StackOverflowErrortanto in tanto.

Il secondo aspetto è che Akka è configurato per arrestare l'intero sistema dell'attore in caso di errore fatale JVM (ad es. StackOverflowError).

Il terzo aspetto è che questo sistema attore è incorporato in un'app Web (per WTF-ish, legacy, ragioni), quindi quando il sistema attore viene spento, l'app Web non lo è. L'effetto netto è che su una StackOverflowErrornostra applicazione di elaborazione dei lavori diventa solo un'app Web vuota.

Come soluzione rapida ho dovuto catturare l' StackOverflowErroressere lanciato, in modo che il pool di thread del sistema attore non venisse demolito. Questo mi ha portato a pensare che forse a volte va bene cogliere tali errori soprattutto in contesti come questo? Quando c'è un pool di thread che elabora attività arbitrarie? A differenza di un OutOfMemoryErrornon riesco a immaginare come si StackOverflowErrorpossa lasciare un'applicazione in uno stato incoerente. Lo stack viene cancellato dopo tale errore, quindi il calcolo può continuare normalmente. Ma forse mi manca qualcosa di importante.

Inoltre, si noti che sono tutto per correggere l'errore in primo luogo (in realtà ho già risolto un SOE in questa stessa app qualche giorno fa), ma davvero non so quando questo potrebbe sorgere un tipo di situazione.

Perché sarebbe meglio riavviare il processo JVM invece di catturare StackOverflowError, contrassegnare quel lavoro come fallito e continuare con la mia attività?

C'è qualche motivo convincente per non catturare mai SOE? Tranne "buone pratiche", che è un termine vago che non mi dice nulla.


1
un'altra opzione sarebbe quella di aumentare lo spazio dello stack disponibile sulla JVM
maniaco del cricchetto

3
@ratchetfreak: gli StackOverflowExceptions sono generalmente dovuti a una catena non terminante di chiamate al metodo - aumentando lo spazio dello stack si aumenterebbe quindi il costo della memoria di un nuovo thread senza alcun vantaggio.
jhominal

1
Almeno una SOE era legittima perché l'input era molto grande. Sfortunatamente, gestirlo con un'implementazione ricorsiva (regex impl. Di Java) non è stata una buona idea. Ad ogni modo, anche quando il calcolo è terminato, non si sa se la nuova dimensione dello stack è abbastanza grande per altri calcoli.
Ionuț G. Stan,

2
Non dovrebbe essere migrato a Sta ... Oh, aspetta ... non importa. :-)
Blrfl,

Per quanto riguarda la tua libreria con errori. Dovresti davvero migrare quella funzione di manipolazione del pdf nel proprio processo in modo da poter lasciare che il sistema operativo lo uccida.
Esben Skov Pedersen,

Risposte:


44

Come regola generale, se non fosse mai assolutamente, mai accettabile fare qualcosa, e ci fosse un accordo al riguardo, gli implementatori del linguaggio non lo avrebbero permesso. Non ci sono quasi massime così nette all'unanimità. (Fortunatamente, perché questo è ciò che ci tiene programmatori umani nei lavori!)

Sembra quasi che tu abbia trovato una situazione in cui la cattura di questo errore è l'opzione migliore per te: consente alla tua applicazione di funzionare, mentre tutte le altre alternative no, ed è quello che conta alla fine. Tutte le "migliori pratiche" sono semplicemente sommazioni di lunghe esperienze con molti casi che possono essere generalmente utilizzate al posto di un'analisi dettagliata di un caso specifico per risparmiare tempo; nel tuo caso, hai già fatto l'analisi specifica e hai ottenuto un risultato diverso. Congratulazioni, sei capace di pensiero indipendente!

(Detto questo, sicuramente ci sono situazioni in cui un overflow dello stack può lasciare un'applicazione incoerente proprio come un esaurimento della memoria. Immagina solo che un oggetto sia costruito e quindi inizializzato con l'aiuto di chiamate di metodi interne annidate - se uno di loro lancia, l'oggetto potrebbe benissimo trovarsi in uno stato che non dovrebbe essere possibile, proprio come se un'allocazione fosse fallita. Ma ciò non significa che la tua soluzione non potrebbe essere ancora la migliore.)


3
Grazie. I miei dubbi si sono in qualche modo rafforzati dopo aver scoperto che .NET ha fatto StackOverflowExceptionun'eccezione irreperibile. Lo so, è una piattaforma diversa, ma ho pensato che avrebbero potuto avere un motivo. Inoltre, il punto relativo all'inizializzazione dell'oggetto è perfetto. Questo mi porta a pensare che dovrei catturare questa SOE alcuni strati di astrazione qui sotto, in modo da non catturare la SOE "sbagliata".
Ionuț G. Stan,

14
+1: le migliori pratiche dovrebbero sempre fornire spiegazioni sul perché e in quale contesto siano "migliori", in modo che tu possa giudicare se si applicano al tuo caso specifico.
Michael Borgwardt,

situations heredovrebbe essere situations where.
Servito il

2

Non so se ci siano rischi specifici per JVM qui, ma nel complesso sembra abbastanza ragionevole.

Ad esempio, esistono algoritmi ricorsivi, come ingenui quicksort, che hanno la log(n)profondità dello stack in un caso tipico, ma nel caso peggiore si degradano a profondità nche possono far esplodere lo stack.

Il caso peggiore è raro e è improbabile che si verifichi di nuovo se si riavvia l'ordinamento sul set parzialmente ordinato, quindi ha molto senso rilevare l'eccezione di overflow dello stack quando si verifica e riavviare il lavoro invece di cercare di impedire che si verifichino errori o uccisioni intera applicazione.

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.