Antworten:
Suchen Sie nach wiederkehrenden Methodenaufrufen. Dies wird hauptsächlich verursacht, wenn eine Methode rekursiv aufgerufen wird. Ein einfaches Beispiel ist
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Hier das System.out.println (i); wird wiederholt zum Stapeln verschoben, wenn die testMethod aufgerufen wird.
Eines der (optionalen) Argumente für die JVM ist die Stapelgröße. Es ist -Xss. Ich weiß nicht, was der Standardwert ist, aber wenn die Gesamtmenge des Materials auf dem Stapel diesen Wert überschreitet, wird dieser Fehler angezeigt.
Im Allgemeinen ist eine unendliche Rekursion die Ursache dafür. Wenn Sie dies jedoch sehen würden, hätte Ihre Stapelverfolgung mehr als 5 Frames.
Versuchen Sie, ein -Xss-Argument hinzuzufügen (oder den Wert von eins zu erhöhen), um festzustellen, ob dies nicht mehr funktioniert.
Was tatsächlich einen java.lang.StackOverflowError verursacht, ist normalerweise eine unbeabsichtigte Rekursion. Für mich ist es oft, wenn ich beabsichtigte, eine Supermethode für die überschriebene Methode aufzurufen. Wie in diesem Fall:
public class Vehicle {
public void accelerate(float acceleration, float maxVelocity) {
// set the acceleration
}
}
public class SpaceShip extends Vehicle {
@Override
public void accelerate(float acceleration, float maxVelocity) {
// update the flux capacitor and call super.accelerate
// oops meant to call super.accelerate(acceleration, maxVelocity);
// but accidentally wrote this instead. A StackOverflow is in our future.
this.accelerate(acceleration, maxVelocity);
}
}
Zunächst ist es hilfreich zu wissen, was hinter den Kulissen passiert, wenn wir eine Funktion aufrufen. Die Argumente und die Adresse, an der die Methode aufgerufen wurde, werden auf den Stapel verschoben (siehe http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ), damit die aufgerufene Methode auf die Argumente zugreifen kann und wann Wenn die aufgerufene Methode abgeschlossen ist, kann die Ausführung nach dem Aufruf fortgesetzt werden. Da wir this.accelerate (Beschleunigung, maxVelocity) rekursiv aufrufen (Rekursion ist lose, wenn sich eine Methode selbst aufruft. Weitere Informationen finden Sie unter http://en.wikipedia.org/wiki/Recursion_(computer_science).) Wir befinden uns in einer Situation, die als unendliche Rekursion bekannt ist, und stapeln die Argumente und die Rücksprungadresse auf dem Aufrufstapel. Da der Aufrufstapel endlich ist, geht uns schließlich der Speicherplatz aus. Der Platzmangel auf dem Aufrufstapel wird als Überlauf bezeichnet. Dies liegt daran, dass wir versuchen, mehr Stapelspeicher als wir zu verwenden, und die Daten den Stapel buchstäblich überlaufen. In der Programmiersprache Java führt dies zur Laufzeitausnahme java.lang.StackOverflow und stoppt das Programm sofort.
Das obige Beispiel ist etwas vereinfacht (obwohl es mir mehr passiert, als ich zugeben möchte). Dasselbe kann auf eine rundere Art und Weise passieren, was es etwas schwieriger macht, es aufzuspüren. Im Allgemeinen ist der StackOverflow jedoch in der Regel recht einfach aufzulösen, sobald er auftritt.
Theoretisch ist es auch möglich, einen Stapelüberlauf ohne Rekursion zu haben, aber in der Praxis scheint dies ein ziemlich seltenes Ereignis zu sein.
java.lang.StackOverflowError
Der Fehler java.lang.StackOverflowError
wird angezeigt, um anzuzeigen, dass der Stapel der Anwendung aufgrund einer tiefen Rekursion erschöpft ist, dh Ihr Programm / Skript rekursiert zu tief.
Die StackOverflowError
Extended- VirtualMachineError
Klasse, die angibt, dass der JVM die Ressourcen ausgegangen sind oder ausgegangen sind und nicht weiter ausgeführt werden können. Das, VirtualMachineError
was die Error
Klasse erweitert, wird verwendet, um die schwerwiegenden Probleme anzuzeigen, die eine Anwendung nicht abfangen sollte. Eine Methode darf solche Fehler nicht deklarierenthrow
Klausel, da diese Fehler abnormale Bedingungen sind, von denen nie erwartet wurde, dass sie auftreten.
Minimal, Complete, and Verifiable Example
::
package demo;
public class StackOverflowErrorExample {
public static void main(String[] args)
{
StackOverflowErrorExample.recursivePrint(1);
}
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if(num == 0)
return;
else
recursivePrint(++num);
}
}
Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
.
.
.
at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
Wenn ein Funktionsaufruf von einer Java - Anwendung aufgerufen wird, ein Stapelrahmen wird auf dem zugeordneten Call - Stack . Das stack frame
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ückgekehrt ist. Wenn kein Platz für einen neuen Stapelrahmen vorhanden ist, wird derStackOverflowError
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. Recursion
eine der leistungsstärksten Allzweck-Programmiertechniken, die jedoch mit Vorsicht angewendet werden muss, damit dieStackOverflowError
damit dies vermieden wird.
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ückgekehrt ist. Wenn kein Platz für einen neuen Stack-Frame vorhanden ist, wird der StackOverflowError 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.
Guck dir das mal bitte an
Ich habe ein Programm mit Ruhezustand erstellt, in dem ich zwei POJO-Klassen erstellt habe, beide mit einem Objekt voneinander als Datenelemente. Als ich in der Hauptmethode versuchte, sie in der Datenbank zu speichern, bekam ich auch diesen Fehler.
Dies geschieht, weil beide Klassen aufeinander verweisen und somit eine Schleife erstellen, die diesen Fehler verursacht.
Überprüfen Sie also, ob in Ihrem Programm solche Beziehungen bestehen.
Lösung für Benutzer im Ruhezustand beim Parsen von Daten:
Ich hatte diesen Fehler, weil ich eine Liste von Objekten analysiert habe, die auf beiden Seiten @OneToMany
und zugeordnet sind@ManyToOne
analysierte, die json mit jackson zugeordnet waren, was eine Endlosschleife verursachte.
Wenn Sie sich in derselben Situation befinden, können Sie dies mithilfe von @JsonManagedReference
und @JsonBackReference
Anmerkungen lösen .
Definitionen aus der API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
Annotation, die angibt, dass annotierte Eigenschaften Teil einer bidirektionalen Verknüpfung zwischen Feldern sind. und dass seine Rolle "Eltern" (oder "Vorwärts") Link ist. Der Werttyp (Klasse) der Eigenschaft muss eine einzige kompatible Eigenschaft haben, die mit JsonBackReference versehen ist. Die Verknüpfung wird so behandelt, dass die mit dieser Anmerkung kommentierte Eigenschaft normal behandelt wird (normal serialisiert, keine spezielle Behandlung für die Deserialisierung). Es ist die übereinstimmende Rückreferenz, die eine besondere Behandlung erfordert
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Anmerkung, die angibt, dass die zugeordnete Eigenschaft Teil der bidirektionalen Verknüpfung zwischen Feldern ist. und dass seine Rolle "Kind" (oder "Zurück") Link ist. Der Werttyp der Eigenschaft muss eine Bean sein: Es kann sich nicht um eine Sammlung, eine Zuordnung, ein Array oder eine Aufzählung handeln. Die Verknüpfung wird so behandelt, dass die mit dieser Anmerkung versehene Eigenschaft nicht serialisiert wird. und während der Deserialisierung wird sein Wert auf eine Instanz gesetzt, die den "verwalteten" (Vorwärts-) Link hat.
Beispiel:
Owner.java:
@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;
Car.java:
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
Eine andere Lösung ist die Verwendung, bei @JsonIgnore
der das Feld nur auf Null gesetzt wird.
Stapelüberlauf-Ausnahmen können auftreten, wenn ein Thread-Stapel weiter an Größe zunimmt, bis die maximale Grenze erreicht ist.
Anpassen der Optionen für Stapelgrößen (Xss und Xmso) ...
Ich schlage vor, Sie sehen diesen Link: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Es gibt viele mögliche Ursachen für einen StackOverflowError, wie Sie im Link sehen können ....
In meinem Fall habe ich zwei Aktivitäten. In der zweiten Aktivität habe ich vergessen, die onCreate-Methode super zu setzen.
super.onCreate(savedInstanceState);
StackOverflowError
, tue ich nicht, dass es die Frage beantwortet. Ich denke, eine richtige Antwort sollte entweder andere Möglichkeiten auflisten, um diese Ausnahme zu erhalten, als zu viel Rekursion zu verwenden, oder sagen, dass es definitiv keine andere Möglichkeit gibt, eine solche Ausnahme zu erhalten, als sie manuell auszulösen.