Co może spowodować java.lang.StackOverflowError
? Wydruk stosu, który otrzymuję, nie jest wcale zbyt głęboki (tylko 5 metod).
87
Co może spowodować java.lang.StackOverflowError
? Wydruk stosu, który otrzymuję, nie jest wcale zbyt głęboki (tylko 5 metod).
Odpowiedzi:
Sprawdź, czy nie występują rekuzyjne wywołania metod. Głównie jest to spowodowane rekurencyjnym wywołaniem metody. Prosty przykład to
public static void main(String... args) { Main main = new Main(); main.testMethod(1); } public void testMethod(int i) { testMethod(i); System.out.println(i); }
Tutaj System.out.println (i); będzie wielokrotnie umieszczany w stosie, gdy wywoływana jest metoda testMethod.
źródło
Jednym z (opcjonalnych) argumentów JVM jest rozmiar stosu. To jest -Xss. Nie wiem, jaka jest wartość domyślna, ale jeśli całkowita ilość rzeczy na stosie przekroczy tę wartość, otrzymasz ten błąd.
Generalnie przyczyną tego jest nieskończona rekurencja, ale gdybyś to zobaczył, ślad stosu miałby więcej niż 5 ramek.
Spróbuj dodać argument -Xss (lub zwiększyć wartość jednego), aby zobaczyć, czy to zniknie.
źródło
To, co faktycznie powoduje błąd java.lang.StackOverflowError, to zazwyczaj niezamierzona rekursja. Dla mnie często zdarza się, że zamierzałem wywołać super metodę dla metody przesłoniętej. Tak jak w tym przypadku:
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); } }
Po pierwsze, warto wiedzieć, co dzieje się za kulisami, gdy wywołujemy funkcję. Argumenty i adres miejsca wywołania metody są umieszczane na stosie (patrz http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ), aby wywoływana metoda mogła uzyskać dostęp do argumentów, a kiedy wywołana metoda jest zakończona, wykonanie może być kontynuowane po wywołaniu. Ale ponieważ nazywamy this.accelerate (przyspieszenie, maxVelocity) rekurencyjnie (rekurencja jest luźna, gdy metoda wywołuje samą siebie. Aby uzyskać więcej informacji, zobacz http://en.wikipedia.org/wiki/Recursion_(computer_science)) znajdujemy się w sytuacji znanej jako nieskończona rekurencja i wciąż gromadzimy argumenty i adres zwrotny na stosie wywołań. Ponieważ stos wywołań ma ograniczony rozmiar, w końcu zabraknie nam miejsca. Brak miejsca na stosie wywołań jest nazywany przepełnieniem. Dzieje się tak, ponieważ staramy się wykorzystać więcej miejsca na stosie niż mamy, a dane dosłownie przepełniają stos. W języku programowania Java powoduje to wyjątek środowiska wykonawczego java.lang.StackOverflow i natychmiastowe zatrzymanie programu.
Powyższy przykład jest nieco uproszczony (chociaż zdarza mi się to bardziej, niż bym chciał przyznać). To samo może się zdarzyć w bardziej okrągły sposób, co utrudnia wytropienie. Jednak ogólnie rzecz biorąc, StackOverflow jest zwykle dość łatwy do rozwiązania, gdy już się pojawi.
Teoretycznie możliwe jest również przepełnienie stosu bez rekursji, ale w praktyce wydaje się, że jest to dość rzadkie zdarzenie.
źródło
Co jest
java.lang.StackOverflowError
Błąd
java.lang.StackOverflowError
jest generowany, aby wskazać, że stos aplikacji został wyczerpany z powodu głębokiej rekurencji, tj. Twój program / skrypt powtarza się zbyt głęboko.Detale
StackOverflowError
RozszerzaVirtualMachineError
klasę, która wskazuje, że JVM zostały lub nie zabraknie zasobów i nie może pracować dalej. ElementVirtualMachineError
rozszerzającyError
klasę służy do wskazania tych poważnych problemów, których aplikacja nie powinna przechwytywać. Metoda może nie deklarować takich błędów w swojejthrow
klauzuli, ponieważ te błędy są warunkami anormalnymi, których nigdy nie oczekiwano.Przykład
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); } }
Wyjście konsoli
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)
Wyjaśnienie
Gdy wywołanie funkcji jest wywoływane przez aplikację Java, na stosie wywołań alokowana jest ramka stosu .
stack frame
Zawiera parametry metody wywołaniu jego lokalnych parametrów oraz adres zwrotny metody. Adres zwrotny oznacza punkt wykonania, z którego wykonanie programu będzie kontynuowane po powrocie wywołanej metody. Jeśli nie ma miejsca na nową ramkę stosu,StackOverflowError
jest ona generowana przez wirtualną maszynę języka Java (JVM).Najczęstszym przypadkiem, który może wyczerpać stos aplikacji Java, jest rekurencja. W rekurencji metoda wywołuje się podczas wykonywania.
Recursion
jedna z najpotężniejszych technik programowania ogólnego przeznaczenia, ale należy jej używać ostrożnie,StackOverflowError
aby jej uniknąć.Bibliografia
źródło
Gdy wywołanie funkcji jest wywoływane przez aplikację Java, na stosie wywołań alokowana jest ramka stosu. Ramka stosu zawiera parametry wywoływanej metody, jej parametry lokalne oraz adres zwrotny metody.
Adres zwrotny oznacza punkt wykonania, z którego będzie kontynuowane wykonanie programu po powrocie wywołanej metody. Jeśli nie ma miejsca na nową ramkę stosu, wówczas StackOverflowError jest generowany przez wirtualną maszynę Java (JVM) .
Najczęstszym przypadkiem, który może wyczerpać stos aplikacji Java, jest rekurencja.
Proszę spojrzeć
Jak rozwiązać StackOverflowError
źródło
Rozwiązanie dla użytkowników Hibernate'a podczas analizowania danych:
Wystąpił ten błąd, ponieważ analizowałem listę obiektów zmapowanych po obu stronach
@OneToMany
i@ManyToOne
do json za pomocą json, co spowodowało nieskończoną pętlę.Jeśli jesteś w tej samej sytuacji, możesz rozwiązać ten problem za pomocą adnotacji
@JsonManagedReference
i@JsonBackReference
.Definicje z API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Przykład:
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;
Innym rozwiązaniem jest użycie,
@JsonIgnore
które po prostu ustawi wartość null w polu.źródło
Stworzyłem program z hibernacją, w którym stworzyłem dwie klasy POJO, obie z obiektami będącymi sobą jako członkami danych. Gdy w głównej metodzie próbowałem je zapisać w bazie danych to też wyskoczył mi ten błąd.
Dzieje się tak, ponieważ obie klasy odwołują się do siebie, tworząc pętlę, która powoduje ten błąd.
Sprawdź więc, czy w twoim programie istnieją takie relacje.
źródło
Wyjątki związane z przepełnieniem stosu mogą wystąpić, gdy rozmiar stosu wątków nadal rośnie, aż do osiągnięcia maksymalnego limitu.
Dostosowywanie opcji rozmiarów stosu (Xss i Xmso) ...
Sugeruję, abyś zobaczył ten link: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Istnieje wiele możliwych przyczyn StackOverflowError, jak widać w linku ....
źródło
W moim przypadku mam dwa zajęcia. W drugim ćwiczeniu zapomniałem postawić super na metodzie onCreate.
super.onCreate(savedInstanceState);
źródło
StackOverflowError
, nie sądzę, że jest to odpowiedź na pytanie. Myślę, że prawidłowa odpowiedź powinna albo wymienić inne sposoby uzyskania tego wyjątku niż użycie zbyt dużej rekurencji lub powiedzieć, że zdecydowanie nie ma innego sposobu na uzyskanie takiego wyjątku, jak tylko wyrzucenie go ręcznie.