¿Qué puede causar un java.lang.StackOverflowError
? La copia impresa de la pila que obtengo no es muy profunda (solo 5 métodos).
Respuestas:
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.
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.
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.
java.lang.StackOverflowError
El error se java.lang.StackOverflowError
produce 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.
La clase StackOverflowError
amplía VirtualMachineError
que indica que la JVM se ha quedado o se ha quedado sin recursos y no puede seguir funcionando. El VirtualMachineError
que extiende la Error
clase 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 throw
cláusula porque estos errores son condiciones anormales que nunca se esperaba que ocurrieran.
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)
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 frame
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 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, StackOverflowError
el 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. Recursion
una de las técnicas de programación de propósito general más poderosas, pero debe usarse con precaución para StackOverflowError
evitarlo.
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
Solución para usuarios de Hibernate al analizar datos:
Tuve este error porque estaba analizando una lista de objetos mapeados en ambos lados @OneToMany
y @ManyToOne
json usando jackson, lo que provocó un bucle infinito.
Si se encuentra en la misma situación, puede solucionarlo utilizando las anotaciones @JsonManagedReference
y @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 @JsonIgnore
que simplemente establecerá nulo en el campo.
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.
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 ...
En mi caso tengo dos actividades. En la segunda actividad, olvidé poner super en el método onCreate.
super.onCreate(savedInstanceState);
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.