¿Qué causa un java.lang.StackOverflowError?

Respuestas:

59

Compruebe si hay llamadas recusivas a los métodos. Principalmente se produce cuando hay una llamada recursiva a un método. Un ejemplo simple es

public static void main(String... args) {
    Main main = new Main();

    main.testMethod(1);
}

public void testMethod(int i) {
    testMethod(i);

    System.out.println(i);
}

Aquí el System.out.println (i); se enviará repetidamente a la pila cuando se llame a testMethod.

Thota Srinath
fuente
1
Creo que tienes razón. Pero cuál es la solución. Porque estamos haciendo un método de recusación, significa que lo necesitamos. No queremos hacer cambios de método. Entonces, ¿cómo se puede solucionar este error?
Ajay Sharma
1
¡O estás entrando en un bucle infinito!
yalematta
@yalematta, cualquier método recursivo debe tener una condición para salir. Por lo tanto, verifique si su método recursivo está implementado correctamente y finaliza dependiendo de alguna condición.
Ayaz Alifov
@AjaySharma Necesitamos diseñar nuestro sistema para que se ajuste a los límites de memoria disponibles que asignamos a JVM. Si el sistema se comporta de manera incómoda con el siguiente error, entonces debemos verificar nuestra base de código.
Thota Srinath
23

Uno de los argumentos (opcionales) de la JVM es el tamaño de la pila. Es -Xss. No sé cuál es el valor predeterminado, pero si la cantidad total de cosas en la pila excede ese valor, obtendrá ese error.

Generalmente, la recursividad infinita es la causa de esto, pero si estuviera viendo eso, su seguimiento de pila tendría más de 5 marcos.

Intente agregar un argumento -Xss (o aumentar el valor de uno) para ver si esto desaparece.

nsayer
fuente
10

Lo que en realidad causa un java.lang.StackOverflowError es típicamente una recursividad involuntaria. Para mí, es a menudo cuando tenía la intención de llamar a un súper método para el método invalidado. Como en este 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); 
    }
}

Primero, es útil saber qué sucede detrás de escena cuando llamamos a una función. Los argumentos y la dirección de donde se llamó al método se insertan en la pila (consulte http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ) para que el método llamado pueda acceder a los argumentos y para que cuando el método llamado se completa, la ejecución puede continuar después de la llamada. Pero como llamamos a this.accelerate (aceleración, maxVelocity) de forma recursiva (la recursión es poco estricta cuando un método se llama a sí mismo. Para obtener más información, consulte http://en.wikipedia.org/wiki/Recursion_(computer_science)) nos encontramos en una situación conocida como recursividad infinita y seguimos acumulando los argumentos y la dirección de retorno en la pila de llamadas. Dado que la pila de llamadas tiene un tamaño finito, eventualmente nos quedamos sin espacio. La falta de espacio en la pila de llamadas se conoce como desbordamiento. Esto se debe a que estamos tratando de usar más espacio de pila del que tenemos y los datos literalmente desbordan la pila. En el lenguaje de programación Java, esto da como resultado la excepción de tiempo de ejecución java.lang.StackOverflow e inmediatamente detendrá el programa.

El ejemplo anterior está algo simplificado (aunque me pasa más de lo que me gustaría admitir). Lo mismo puede suceder de una manera más redonda, lo que hace que sea un poco más difícil de localizar. Sin embargo, en general, StackOverflow suele ser bastante fácil de resolver, una vez que ocurre.

En teoría, también es posible tener un desbordamiento de pila sin recursividad, pero en la práctica, parecería ser un evento bastante raro.

ptoinson
fuente
8

Que es java.lang.StackOverflowError

El error se java.lang.StackOverflowErrorproduce para indicar que la pila de la aplicación se agotó, debido a una recursividad profunda, es decir, su programa / secuencia de comandos se repite demasiado.

Detalles

La clase StackOverflowErroramplía VirtualMachineErrorque indica que la JVM se ha quedado o se ha quedado sin recursos y no puede seguir funcionando. El VirtualMachineErrorque extiende la Errorclase se usa para indicar aquellos problemas serios que una aplicación no debería detectar. Un método puede no declarar tales errores en su throwcláusula porque estos errores son condiciones anormales que nunca se esperaba que ocurrieran.

Un ejemplo

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

}

Salida de consola

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)

Explicacion

Cuando una aplicación Java invoca una llamada a una función, se asigna un marco de pila en la pila de llamadas . El stack framecontiene los parámetros del método invocado, sus parámetros locales, y la dirección de retorno del método. La dirección de retorno denota el punto de ejecución desde el cual, la ejecución del programa continuará después de que regrese el método invocado. Si no hay espacio para un nuevo marco de pila, StackOverflowErrorel Java Virtual Machine (JVM) lo lanza.

El caso más común que posiblemente puede agotar la pila de una aplicación Java es la recursividad. En recursividad, un método se invoca a sí mismo durante su ejecución. Recursionuna de las técnicas de programación de propósito general más poderosas, pero debe usarse con precaución para StackOverflowErrorevitarlo.

Referencias

DebanjanB
fuente
4

Cuando una aplicación Java invoca una llamada a una función, se asigna un marco de pila en la pila de llamadas. El marco de pila contiene los parámetros del método invocado, sus parámetros locales y la dirección de retorno del método.

La dirección de retorno indica el punto de ejecución desde el cual, la ejecución del programa continuará después de que regrese el método invocado. Si no hay espacio para un nuevo marco de pila, la máquina virtual Java (JVM) lanza StackOverflowError .

El caso más común que posiblemente puede agotar la pila de una aplicación Java es la recursividad.

Por favor échale un vistazo

Cómo resolver StackOverflowError

IntelliJ Amiya
fuente
3

Solución para usuarios de Hibernate al analizar datos:

Tuve este error porque estaba analizando una lista de objetos mapeados en ambos lados @OneToManyy @ManyToOnejson usando jackson, lo que provocó un bucle infinito.

Si se encuentra en la misma situación, puede solucionarlo utilizando las anotaciones @JsonManagedReferencey @JsonBackReference.

Definiciones de API:

  • JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):

    Anotación utilizada para indicar que la propiedad anotada es parte de un vínculo bidireccional entre campos; y que su función es el enlace "padre" (o "reenvío"). El tipo de valor (clase) de propiedad debe tener una única propiedad compatible anotada con JsonBackReference. La vinculación se maneja de manera que la propiedad anotada con esta anotación se maneja normalmente (serializada normalmente, sin manejo especial para deserialización); es la referencia posterior coincidente que requiere un manejo especial

  • JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):

    Anotación utilizada para indicar que la propiedad asociada es parte de un vínculo bidireccional entre campos; y que su función es el enlace "secundario" (o "posterior"). El tipo de valor de la propiedad debe ser un bean: no puede ser una colección, mapa, matriz o enumeración. La vinculación se maneja de tal manera que la propiedad anotada con esta anotación no se serializa; y durante la deserialización, su valor se establece en la instancia que tiene el enlace "administrado" (reenvío).

Ejemplo:

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;

Otra solución es usar @JsonIgnoreque simplemente establecerá nulo en el campo.

Emerica
fuente
2

Creé un programa con hibernación, en el que creé dos clases POJO, ambas con un objeto el uno del otro como miembros de datos. Cuando en el método principal intenté guardarlos en la base de datos, también obtuve este error.

Esto sucede porque ambas clases se refieren entre sí, por lo que se crea un bucle que causa este error.

Por lo tanto, verifique si existe ese tipo de relaciones en su programa.

Singh
fuente
1

Las excepciones de desbordamiento de pila pueden ocurrir cuando una pila de subprocesos continúa creciendo en tamaño hasta alcanzar el límite máximo.

Ajuste de las opciones de Tamaños de pila (Xss y Xmso) ...

Le sugiero que vea este enlace: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Hay muchas causas posibles para un StackOverflowError, como puede ver en el enlace ...

Marzieh Ghadirinia
fuente
Las respuestas de solo enlace generalmente no son aceptables; los enlaces se rompen, lo que invalidaría totalmente la respuesta. Proporcione algo de contexto, código y una explicación de la respuesta en lugar de solo un enlace.
Jay
0

En mi caso tengo dos actividades. En la segunda actividad, olvidé poner super en el método onCreate.

super.onCreate(savedInstanceState);
Julz Etnalob
fuente
Incluso si es una forma posible de plantear una StackOverflowError, no creo que esté respondiendo a la pregunta. Creo que una respuesta adecuada debería enumerar otras formas de obtener esta excepción además de usar demasiada recursividad o decir que definitivamente no hay otra forma de obtener dicha excepción, excepto lanzarla manualmente.
JojOatXGME