Cosa può causare un java.lang.StackOverflowError
? La stampa dello stack che ottengo non è affatto molto profonda (solo 5 metodi).
Risposte:
Verifica la presenza di chiamate recusive per metodi. Principalmente è causato quando c'è una chiamata ricorsiva per un metodo. Un semplice esempio è
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Qui il System.out.println (i); verrà ripetutamente inserito nello stack quando viene chiamato testMethod.
Uno degli argomenti (facoltativi) della JVM è la dimensione dello stack. È -Xss. Non so quale sia il valore predefinito, ma se la quantità totale di cose nello stack supera quel valore, riceverai quell'errore.
Generalmente, la ricorsione infinita è la causa di ciò, ma se lo vedessi, la tua traccia dello stack avrebbe più di 5 frame.
Prova ad aggiungere un argomento -Xss (o ad aumentare il valore di uno) per vedere se scompare.
Ciò che effettivamente causa un java.lang.StackOverflowError è in genere la ricorsione non intenzionale. Per me è spesso quando intendevo chiamare un super metodo per il metodo overidden. Come in questo caso:
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);
}
}
Innanzitutto, è utile sapere cosa succede dietro le quinte quando chiamiamo una funzione. Gli argomenti e l'indirizzo di dove è stato chiamato il metodo vengono inseriti nello stack (vedere http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ) in modo che il metodo chiamato possa accedere agli argomenti e in modo che quando il metodo chiamato è completato, l'esecuzione può continuare dopo la chiamata. Ma poiché chiamiamo this.accelerate (acceleration, maxVelocity) in modo ricorsivo (la ricorsione è approssimativa quando un metodo chiama se stesso. Per maggiori informazioni vedi http://en.wikipedia.org/wiki/Recursion_(computer_science)) siamo in una situazione nota come ricorsione infinita e continuiamo ad accumulare argomenti e indirizzo di ritorno nello stack di chiamate. Poiché lo stack di chiamate è di dimensioni finite, alla fine lo spazio è esaurito. L'esaurimento dello spazio nello stack di chiamate è noto come overflow. Questo perché stiamo cercando di utilizzare più spazio dello stack di quello che abbiamo e i dati traboccano letteralmente dallo stack. Nel linguaggio di programmazione Java, ciò provoca l'eccezione di runtime java.lang.StackOverflow e interromperà immediatamente il programma.
L'esempio sopra è in qualche modo semplificato (anche se mi capita più di quanto vorrei ammettere). La stessa cosa può accadere in un modo più circolare, rendendolo un po 'più difficile da rintracciare. Tuttavia, in generale, StackOverflow è di solito abbastanza facile da risolvere, una volta che si verifica.
In teoria, è anche possibile avere uno stack overflow senza ricorsione, ma in pratica sembrerebbe essere un evento abbastanza raro.
java.lang.StackOverflowError
L'errore java.lang.StackOverflowError
viene generato per indicare che lo stack dell'applicazione è stato esaurito, a causa di una profonda ricorsione, ovvero il programma / script ricorre troppo in profondità.
La classe StackOverflowError
extends VirtualMachineError
che indica che la JVM è stata o ha esaurito le risorse e non può funzionare ulteriormente. L' VirtualMachineError
elemento che estende la Error
classe viene utilizzato per indicare quei gravi problemi che un'applicazione non dovrebbe rilevare. Un metodo potrebbe non dichiarare tali errori nella sua throw
clausola perché questi errori sono condizioni anomale che non si sarebbero mai aspettate.
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)
Quando una chiamata di funzione viene richiamata da un'applicazione Java, uno stack frame viene allocato sullo stack di chiamate . Il stack frame
contiene i parametri del metodo richiamato, i parametri locali, e l'indirizzo di ritorno del metodo. L'indirizzo di ritorno denota il punto di esecuzione dal quale, l'esecuzione del programma deve continuare dopo il ritorno del metodo invocato. Se non c'è spazio per un nuovo stack frame, StackOverflowError
viene generato dalla Java Virtual Machine (JVM).
Il caso più comune che può esaurire lo stack di un'applicazione Java è la ricorsione. Nella ricorsione, un metodo invoca se stesso durante la sua esecuzione. Recursion
una delle più potenti tecniche di programmazione generica, ma deve essere usata con cautela, in modo che StackOverflowError
possa essere evitata.
Quando una chiamata di funzione viene richiamata da un'applicazione Java, uno stack frame viene allocato sullo stack di chiamate. Lo stack frame contiene i parametri del metodo richiamato, i suoi parametri locali e l'indirizzo di ritorno del metodo.
L'indirizzo di ritorno denota il punto di esecuzione dal quale, l'esecuzione del programma deve continuare dopo il ritorno del metodo invocato. Se non c'è spazio per un nuovo stack frame, lo StackOverflowError viene lanciato dalla Java Virtual Machine (JVM) .
Il caso più comune che può esaurire lo stack di un'applicazione Java è la ricorsione.
Per favore guarda
Soluzione per gli utenti di ibernazione durante l'analisi dei dati:
Ho riscontrato questo errore perché stavo analizzando un elenco di oggetti mappati su entrambi i lati @OneToMany
e@ManyToOne
su json usando jackson che ha causato un ciclo infinito.
Se ti trovi nella stessa situazione puoi risolverlo usando @JsonManagedReference
e@JsonBackReference
annotazioni.
Definizioni dall'API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
Annotazione utilizzata per indicare che la proprietà annotata fa parte di un collegamento bidirezionale tra i campi; e che il suo ruolo è il collegamento "genitore" (o "inoltro"). Il tipo di valore (classe) della proprietà deve avere una singola proprietà compatibile annotata con JsonBackReference. Il collegamento viene gestito in modo tale che la proprietà annotata con questa annotazione venga gestita normalmente (serializzata normalmente, nessuna gestione speciale per la deserializzazione); è il riferimento a ritroso corrispondente che richiede una gestione speciale
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Annotazione utilizzata per indicare che la proprietà associata fa parte del collegamento bidirezionale tra i campi; e che il suo ruolo è il collegamento "figlio" (o "indietro"). Il tipo di valore della proprietà deve essere un bean: non può essere una raccolta, una mappa, un array o un'enumerazione. Il collegamento è gestito in modo tale che la proprietà annotata con questa annotazione non sia serializzata; e durante la deserializzazione, il suo valore è impostato sull'istanza che ha il collegamento "gestito" (in avanti).
Esempio:
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;
Un'altra soluzione è usare @JsonIgnore
che imposterà semplicemente null nel campo.
Ho creato un programma con hibernate, in cui ho creato due classi POJO, entrambe con un oggetto l'una dell'altra come membri dati. Quando nel metodo principale ho provato a salvarli nel database ho ricevuto anche questo errore.
Ciò accade perché entrambe le classi si riferiscono l'una all'altra, creando quindi un ciclo che causa questo errore.
Quindi, controlla se esiste un tale tipo di relazioni nel tuo programma.
Le eccezioni di overflow dello stack possono verificarsi quando uno stack di thread continua a crescere di dimensioni fino a raggiungere il limite massimo.
Regolazione delle opzioni Stack Sizes (Xss e Xmso) ...
Ti suggerisco di vedere questo link: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Ci sono molte possibili cause per uno StackOverflowError, come puoi vedere nel link ....
Nel mio caso ho due attività. Nella seconda attività mi sono dimenticato di mettere super sul metodo onCreate.
super.onCreate(savedInstanceState);
StackOverflowError
, non penso che stia rispondendo alla domanda. Penso che una risposta corretta dovrebbe elencare altri modi per ottenere questa eccezione piuttosto che usare troppa ricorsione o dire che non c'è sicuramente nessun altro modo per ottenere tale eccezione se non lanciarla manualmente.