Ist es * jemals * in Ordnung, StackOverflowError in Java abzufangen?


27

Früher dachte ich, dass es nicht so ist, aber gestern musste ich es tun. Es ist eine Anwendung, die Akka (eine Implementierung des Aktorsystems für die JVM) verwendet, um asynchrone Jobs zu verarbeiten. Einer der Schauspieler führt eine PDF-Manipulation durch, und da die Bibliothek fehlerhaft ist, stirbt sie mitunter mit einem StackOverflowError.

Der zweite Aspekt ist, dass Akka so konfiguriert ist, dass das gesamte Aktorsystem heruntergefahren wird, wenn ein schwerwiegender JVM-Fehler (z. B. StackOverflowError) festgestellt wird.

Der dritte Aspekt ist, dass dieses Darstellersystem in eine Web-App eingebettet ist (aus WTF-Gründen, Legacy-Gründen). Wenn das Darstellersystem heruntergefahren wird, ist dies bei der Web-App nicht der Fall. Der Nettoeffekt ist, dass StackOverflowErrorunsere Jobbearbeitungsanwendung nur noch eine leere Webanwendung ist.

Als schnelle Lösung musste ich das StackOverflowErrorGeworfene auffangen , damit der Threadpool des Darstellersystems nicht abgerissen wird. Das ließ mich denken, dass es vielleicht manchmal in Ordnung ist, solche Fehler zu fangen, besonders in solchen Kontexten? Wenn es einen Thread-Pool gibt, der beliebige Aufgaben verarbeitet? Im Gegensatz zu einem OutOfMemoryErrorkann ich mir nicht vorstellen, wie StackOverflowErrorman eine Anwendung in einem inkonsistenten Zustand belassen kann. Nach einem solchen Fehler wird der Stapel gelöscht, sodass die Berechnung normal fortgesetzt werden kann. Aber vielleicht fehlt mir etwas Wichtiges.

Es sei auch angemerkt, dass ich alles dafür bin, den Fehler an erster Stelle zu beheben (tatsächlich habe ich bereits vor einigen Tagen einen SOE in derselben App behoben), aber ich weiß wirklich nicht, wann dies geschieht Art von Situation kann auftreten.

Warum ist es besser, den JVM-Prozess neu zu starten, anstatt den StackOverflowErrorJob abzufangen, als fehlgeschlagen zu markieren und mit meinem Geschäft fortzufahren?

Gibt es einen zwingenden Grund, SOEs niemals zu fangen? Mit Ausnahme von "Best Practices", einem vagen Begriff, der mir nichts sagt.


1
Eine andere Möglichkeit wäre , den Stapel Speicherplatz auf der JVM zu erhöhen
Ratsche Freak

3
@ratchetfreak: StackOverflowExceptions sind normalerweise auf eine nicht abschließende Kette von Methodenaufrufen zurückzuführen. Wenn Sie den Stapelspeicherplatz erhöhen, erhöhen sich die Speicherkosten eines neuen Threads, ohne dass dies von Vorteil ist.
JHOMINAL

1
Mindestens ein SOE war legitim, da die Eingabe sehr groß war. Leider war es keine gute Idee, es mit einer rekursiven Implementierung (Java-Regex-Impl.) Zu behandeln. Auf jeden Fall wissen Sie nicht, ob die neue Stapelgröße groß genug für andere Berechnungen ist, auch wenn die Beendigung der Berechnung garantiert ist.
Ionuț G. Stan

2
Sollte dies nicht nach Sta migriert werden ... Oh, warte ... egal. :-)
Blrfl

In Bezug auf Ihre Buggy-Bibliothek. Sie sollten diese PDF-Manipulationsfunktion wirklich in einen eigenen Prozess migrieren, damit das Betriebssystem sie beenden kann.
Esben Skov Pedersen

Antworten:


44

Wäre es absolut nie akzeptabel , jemals etwas zu tun, und es bestand Einigkeit darüber, hätten die Sprachimplementierer dies in der Regel nicht zugelassen. Es gibt so gut wie keine eindeutigen Maximen. (Zum Glück, weil das uns menschliche Programmierer in Jobs hält!)

Es sieht so aus, als ob Sie eine Situation gefunden haben, in der das Abfangen dieses Fehlers die beste Option für Sie ist: Ihre Anwendung funktioniert, während dies bei allen anderen Alternativen nicht der Fall ist, und genau das zählt am Ende. Alle "Best Practices" sind einfach Zusammenfassungen langjähriger Erfahrungen mit vielen Fällen, die in der Regel anstelle einer detaillierten Analyse eines bestimmten Falls verwendet werden können, um Zeit zu sparen. In Ihrem Fall haben Sie die spezifische Analyse bereits durchgeführt und ein anderes Ergebnis erhalten. Herzlichen Glückwunsch, Sie können unabhängig denken!

(Das heißt, es gibt sicherlich Situationen, in denen ein Stapelüberlauf eine Anwendung inkonsistent machen kann, genau wie eine Speichererschöpfung. Stellen Sie sich vor, ein Objekt wird mit Hilfe geschachtelter interner Methodenaufrufe erstellt und initialisiert - wenn einer von ihnen das Objekt auslöst befindet sich möglicherweise in einem Zustand, der nicht möglich sein sollte, als wäre eine Zuordnung fehlgeschlagen. Dies bedeutet jedoch nicht, dass Ihre Lösung nicht immer noch die beste sein kann.)


3
Vielen Dank. Meine Zweifel verstärkten sich etwas, als ich herausfand, dass .NET StackOverflowExceptioneine nicht einfangbare Ausnahme darstellt. Ich weiß, es ist eine andere Plattform, aber ich dachte, sie hätten vielleicht einen Grund gehabt. Auch Ihr Punkt in Bezug auf die Objektinitialisierung ist genau richtig. Dies veranlasst mich zu der Überlegung, dass ich dieses SOE ein paar Abstraktionsebenen darunter fangen sollte, damit ich nicht das "falsche" SOE fange.
Ionuț G. Stan

14
+1: Best Practices sollten immer mit Erklärungen darüber versehen sein, warum und in welchem ​​Kontext sie "am besten" sind, damit Sie beurteilen können, ob sie für Ihren speziellen Fall zutreffen.
Michael Borgwardt

situations heresollte sein situations where.
Servy

2

Ich weiß nicht, ob es hier irgendwelche JVM-spezifischen Risiken gibt, aber insgesamt scheint es ziemlich vernünftig.

Zum Beispiel gibt es rekursive Algorithmen wie naive Quicksort, die log(n)in einem typischen Fall eine Stapeltiefe aufweisen, im schlimmsten Fall jedoch eine Verschlechterung auf eine Tiefe n, die den Stapel in die Luft jagen kann.

Der schlimmste Fall ist selten und es ist unwahrscheinlich, dass er erneut auftritt, wenn Sie die Sortierung für die teilweise sortierte Gruppe neu starten. Daher ist es sehr sinnvoll, in diesem Fall eine Stapelüberlauf-Ausnahme abzufangen und die Arbeit neu zu starten, anstatt zu versuchen, das Auftreten oder Beenden von Fehlern zu verhindern gesamte Anwendung.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.