java - ¿Cuándo ocurre StackOverflowError?
recursion stack-overflow (4)
La profundidad depende de dos cosas:
1: El tamaño de la pila.
2: la cantidad de espacio de pila utilizado en cada recursión.
Los parámetros de función, las variables locales y la dirección de retorno están todos asignados en la pila mientras los objetos están asignados en el montón.
Recuperación
Es posible recuperar
try {
myDeepRecursion();
} catch (StackOverflowError e) {
// We are back from deep recursion. Stack should be ok again.
}
Sin embargo, tenga en cuenta lo siguiente con respecto a los errores (del documento API de Java):
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
EDITAR:
Nota de precaución: Si bien capturar excepciones dentro de una función recursiva está bien, no intente detectar errores. Si la pila está llena, el manejo de errores causará nuevos errores. Cosas simples, como una llamada a System.out.println()
fallarán porque no queda espacio en la pila para la dirección de retorno.
Es por eso que los errores se deben atrapar fuera de la función recursiva.
Esta pregunta ya tiene una respuesta aquí:
Según Oracle, un StackOverflowError es:
Lanzado cuando se produce un desbordamiento de la pila porque una aplicación recurre demasiado profundamente.
Sé lo que es la recursividad y normalmente las funciones recursivas, si no se terminan correctamente, conducen a StackOverflowError. Para verificar el número de llamadas recursivas que ocurren antes de lanzar StackOverflowError
, escribí este código:
package ErrorCases;
public class StackOverFlowError {
static int i=0;
void a()
{
//System.out.println("called "+(++i));
try{
++i;
a();
}catch(Error e)
{
System.out.println(e.getClass());
System.out.println(i);
}
}
public static void main(String[] args) {
new StackOverFlowError().a();
}
}
el valor de i
da el recuento de llamadas recursivas a a()
antes de que JVM lanzara StackOverflowError.
El valor de i
es diferente en cada ejecución como:
output 1: class java.lang.StackOverflowError
10466
Output 2: class java.lang.StackOverflowError
10470
Mi pregunta es?
¿Qué tan profunda debe ocurrir la recursión antes de que JVM arroje
StackOverflowError
?¿Podemos recuperarnos una vez que se ha lanzado
StackOverflowError
?
¿Qué tan profunda debe ocurrir la recursión antes de que JVM arroje Error?
Realmente depende de la máquina con la que esté trabajando y su JVM y su configuración. (es 6000 - 8500 en mi configuración actual con muchas tareas en segundo plano) y como mucho, esto lo haces en la aplicación y el método recursivo.
¿Podemos recuperarnos una vez que se ha lanzado Error?
¡No! Java arroja un error, no hay forma de volver a la normalidad. Esa es la principal diferencia entre Excepciones y Errores.
Un error es una subclase de Throwable que indica problemas graves que una aplicación razonable no debería intentar atrapar
Lea más acerca de los errores aquí
Obtenga más información sobre los mitos del tamaño de la pila de Java aquí
Editar:
Todavía puede hacer cosas después de que se produce un error, pero ¿tiene sentido? ¡Tienes un error grave en tu código! ¡No puedes estar seguro de que todo funcione correctamente!
Tu código no termina porque vuelves a llamar al método, que es lo mismo que un bucle sin fin
La razón por la que puede ver diferentes profundidades de pila es que los marcos de pila no son necesariamente del mismo tamaño. El Hotspot JVM, por ejemplo, tiene diferentes marcos de pila para el código compilado JIT y para el código interpretado. El compilador JIT funciona en paralelo con el código de ejecución, por lo que factores externos como la carga en la máquina pueden tener un efecto sobre cuándo / si la JVM comienza a usar marcos de pila JIT.
Una cosa que debes tener en cuenta es el hecho de que cuando obtienes un Error
, casi cualquier cosa que hagas puede causar otro Error
. Por ejemplo, imprimir el nombre de la clase de error en la parte catch
también puede quedarse sin espacio en la pila, por lo que otro Error
arrojará a la pila.
Algunas personas afirman que no puede recuperarse de un Error
porque la JVM se está cerrando. Eso no es correcto; puedes recuperarte de algunos errores. Lo complicado de Error
y OutOfMemoryError
es que, una vez que capturas uno, no tienes absolutamente ninguna garantía del estado del programa; por ejemplo, una estructura de datos clave que use podría estar en un estado inconsistente. Esto hace que la recuperación sea difícil o imposible en general.
Los parámetros y las variables locales se asignan en la pila (con los tipos de referencia, el objeto vive en el montón y una variable hace referencia a ese objeto). La pila generalmente vive en el extremo superior de su espacio de direcciones y, a medida que se utiliza, se dirige hacia la parte inferior del espacio de direcciones (es decir, hacia cero).
Su proceso también tiene un montón, que vive en el extremo inferior de su proceso. A medida que asigna memoria, este montón puede crecer hacia el extremo superior de su espacio de direcciones. Como puede ver, existe la posibilidad de que el montón "colisione" con la pila (un poco como placas techtonic !!!). [fuente]
Por lo tanto, StackOIverflowError dependerá del tamaño de la pila y del tamaño del almacenamiento dinámico, que dependerá de la ejecución hasta la ejecución debido a muchos factores, como GC.
También como su nombre lo dice es Error y no Excepción. No hay recuperación de eso. JVM se cerrará.