Um dies zu beschreiben, lassen Sie uns zunächst verstehen, wie lokale Variablen und Objekte gespeichert werden.
Lokale Variablen werden im Stapel gespeichert :
Wenn Sie sich das Bild ansehen, sollten Sie verstehen können, wie die Dinge funktionieren.
Wenn ein Funktionsaufruf von einer Java-Anwendung aufgerufen wird, wird dem Aufrufstapel ein Stapelrahmen zugewiesen. Der Stapelrahmen enthält die Parameter der aufgerufenen Methode, ihre lokalen Parameter und die Rücksprungadresse der Methode. Die Rücksprungadresse gibt den Ausführungspunkt an, von dem aus die Programmausführung fortgesetzt werden soll, nachdem die aufgerufene Methode zurückgegeben wurde. Wenn kein Platz für einen neuen Stapelrahmen vorhanden ist, StackOverflowError
wird dieser von der Java Virtual Machine (JVM) ausgelöst.
Der häufigste Fall, der möglicherweise den Stapel einer Java-Anwendung erschöpfen kann, ist die Rekursion. Bei der Rekursion ruft sich eine Methode während ihrer Ausführung auf. Rekursion wird als leistungsstarke Allzweckprogrammiertechnik angesehen, muss jedoch mit Vorsicht angewendet werden, um dies zu vermeiden StackOverflowError
.
Ein Beispiel für das Werfen von a StackOverflowError
ist unten dargestellt:
StackOverflowErrorExample.java:
public class StackOverflowErrorExample {
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if (num == 0)
return;
else
recursivePrint(++num);
}
public static void main(String[] args) {
StackOverflowErrorExample.recursivePrint(1);
}
}
In diesem Beispiel definieren wir eine rekursive Methode, recursivePrint
die eine Ganzzahl druckt und sich dann selbst aufruft, wobei die nächste aufeinanderfolgende Ganzzahl ein Argument ist. Die Rekursion endet, bis wir 0
als Parameter übergeben. In unserem Beispiel haben wir jedoch den Parameter von 1 und seinen zunehmenden Followern übergeben. Folglich wird die Rekursion niemals beendet.
Eine Beispielausführung unter Verwendung des -Xss1M
Flags, das die Größe des Thread-Stapels auf 1 MB angibt, ist unten dargestellt:
Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
...
Abhängig von der ursprünglichen Konfiguration der JVM können die Ergebnisse unterschiedlich sein, aber eventuell StackOverflowError
werden sie geworfen. Dieses Beispiel ist ein sehr gutes Beispiel dafür, wie Rekursion Probleme verursachen kann, wenn sie nicht mit Vorsicht implementiert wird.
Umgang mit dem StackOverflowError
Die einfachste Lösung besteht darin, die Stapelspur sorgfältig zu untersuchen und das sich wiederholende Muster der Zeilennummern zu erkennen. Diese Zeilennummern geben den Code an, der rekursiv aufgerufen wird. Sobald Sie diese Zeilen erkannt haben, müssen Sie Ihren Code sorgfältig prüfen und verstehen, warum die Rekursion niemals beendet wird.
Wenn Sie überprüft haben, dass die Rekursion korrekt implementiert ist, können Sie den Stapel vergrößern, um eine größere Anzahl von Aufrufen zu ermöglichen. Abhängig von der installierten Java Virtual Machine (JVM) kann die Standardgröße des Thread-Stacks entweder 512 KB oder 1 MB betragen . Sie können die Thread-Stapelgröße mithilfe des -Xss
Flags erhöhen . Dieses Flag kann entweder über die Projektkonfiguration oder über die Befehlszeile angegeben werden. Das Format des
-Xss
Arguments lautet:
-Xss<size>[g|G|m|M|k|K]