Cosa causa un errore java.lang.StackOverflowError


Risposte:


59

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.


1
Penso che tu abbia ragione. Ma qual è la soluzione. Poiché stiamo creando un metodo che ricicla, significa che ne abbiamo bisogno. Non vogliamo cambiare metodo. Allora come posso risolvere questo errore?
Ajay Sharma

1
o stai entrando in un ciclo infinito!
yalematta

@yalematta, qualsiasi metodo ricorsivo dovrebbe avere una condizione per uscire. Quindi controlla se il tuo metodo ricorsivo è implementato correttamente e termina a seconda di alcune condizioni.
Ayaz Alifov

@AjaySharma Dobbiamo progettare il nostro sistema in modo che si adatti ai limiti di memoria disponibile che abbiamo assegnato a JVM. Se il sistema si comporta in modo strano con il seguente errore, dobbiamo controllare la nostra base di codice.
Thota Srinath

23

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.


10

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.


8

Cosa è java.lang.StackOverflowError

L'errore java.lang.StackOverflowErrorviene generato per indicare che lo stack dell'applicazione è stato esaurito, a causa di una profonda ricorsione, ovvero il programma / script ricorre troppo in profondità.

Dettagli

La classe StackOverflowErrorextends VirtualMachineErrorche indica che la JVM è stata o ha esaurito le risorse e non può funzionare ulteriormente. L' VirtualMachineErrorelemento che estende la Errorclasse viene utilizzato per indicare quei gravi problemi che un'applicazione non dovrebbe rilevare. Un metodo potrebbe non dichiarare tali errori nella sua throwclausola perché questi errori sono condizioni anomale che non si sarebbero mai aspettate.

Un esempio

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);
    }

}

Uscita console

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)

Spiegazione

Quando una chiamata di funzione viene richiamata da un'applicazione Java, uno stack frame viene allocato sullo stack di chiamate . Il stack framecontiene 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, StackOverflowErrorviene 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. Recursionuna delle più potenti tecniche di programmazione generica, ma deve essere usata con cautela, in modo che StackOverflowErrorpossa essere evitata.

Riferimenti


4

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

Come risolvere StackOverflowError


3

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 @OneToManye@ManyToOne su json usando jackson che ha causato un ciclo infinito.

Se ti trovi nella stessa situazione puoi risolverlo usando @JsonManagedReferencee@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 @JsonIgnoreche imposterà semplicemente null nel campo.


2

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.


1

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 ....


Le risposte solo link sono generalmente non accettabili; i collegamenti si interrompono, il che invaliderebbe totalmente la risposta. Fornisci un contesto, un codice e una spiegazione della risposta invece di un semplice collegamento.
Jay

0

Nel mio caso ho due attività. Nella seconda attività mi sono dimenticato di mettere super sul metodo onCreate.

super.onCreate(savedInstanceState);

Anche se è un modo possibile per sollevare a 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.
JojOatXGME
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.