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 StackOverflowError
unsere Jobbearbeitungsanwendung nur noch eine leere Webanwendung ist.
Als schnelle Lösung musste ich das StackOverflowError
Geworfene 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 OutOfMemoryError
kann ich mir nicht vorstellen, wie StackOverflowError
man 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 StackOverflowError
Job 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.
quelle
StackOverflowException
s 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.:-)
Antworten:
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.)
quelle
StackOverflowException
eine 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.situations here
sollte seinsituations where
.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 Tiefen
, 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.
quelle