Ich bin überrascht, wie es möglich ist, die Ausführung fortzusetzen, selbst wenn in Java eine StackOverflowError
aufgetreten ist.
Ich weiß, dass StackOverflowError
eine Unterklasse der Klasse Fehler ist ..__ Die Klasse Fehler wird als "eine Unterklasse von Throwable deklariert, die auf schwerwiegende Probleme hinweist, die eine vernünftige Anwendung nicht versuchen sollte, zu fangen."
Das klingt eher nach einer Empfehlung als nach einer Regel, es ist tatsächlich erlaubt, einen Fehler wie einen StackOverflowError abzufangen, und es liegt im Ermessen des Programmierers, dies nicht zu tun. Und ich habe diesen Code getestet und er wird normalerweise beendet.
public class Test
{
public static void main(String[] args)
{
try {
foo();
} catch (StackOverflowError e) {
bar();
}
System.out.println("normal termination");
}
private static void foo() {
System.out.println("foo");
foo();
}
private static void bar() {
System.out.println("bar");
}
}
Wie kann das sein? Ich denke, wenn der StackOverflowError geworfen wird, sollte der Stack so voll sein, dass kein Platz zum Aufrufen einer anderen Funktion vorhanden ist. Läuft der Fehlerbehandlungsblock in einem anderen Stack oder was ist hier los?
Wenn der Stapel überläuft und StackOverflowError
geworfen wird, wird der Stapel bei der üblichen Ausnahmebehandlung abgewickelt. Abwickeln des Stapels bedeutet:
... bis die Ausnahme abgefangen wird. Dies ist normal (eigentlich notwendig) und unabhängig davon, welche Ausnahme ausgelöst wird und warum. Da Sie die Ausnahme außerhalb des ersten Aufrufs von foo()
abfangen, wurden die Tausende von foo
-Stack-Frames, die den Stack gefüllt haben, abgewickelt, und der größte Teil des Stack kann wieder verwendet werden.
Wenn der StackOverflowError geworfen wird, ist der Stapel voll. Wenn es jedoch catch ist, wurden alle diese foo
-Aufrufe aus dem Stack entfernt. bar
kann normal ausgeführt werden, da der Stapel nicht mehr mit foo
s überläuft. (Beachten Sie, dass ich nicht glaube, dass das JLS garantiert, dass Sie von einem Stapelüberlauf wie diesem wiederherstellen können.)
Wenn StackOverFlow auftritt, springt die JVM auf den Haken und gibt den Stapel frei.
In Ihrem Beispiel werden alle gestapelten Foo los.
Weil der Stack eigentlich nicht überläuft. Ein besserer Name könnte AttemptToOverflowStack sein. Im Wesentlichen bedeutet dies, dass der letzte Versuch, den Stapelrahmen anzupassen, fehlschlägt, da nicht genügend freier Speicherplatz auf dem Stapel vorhanden ist. Der Stapel könnte tatsächlich viel Platz haben, nur nicht genügend Platz. Was auch immer die Operation davon abhängt, ob der Aufruf erfolgreich war (normalerweise ein Methodenaufruf), wird nie ausgeführt und es bleibt nur noch das Programm, das diese Tatsache behandelt. Was bedeutet, dass es sich wirklich nicht von anderen Ausnahmen unterscheidet. Tatsächlich könnten Sie die Ausnahme in der Funktion, die den Aufruf ausführt, abfangen.