java - ¿Qué es un StackOverflowError?




exception-handling stack-overflow (9)

Aquí un ejemplo

public static void main(String[] args) {
    System.out.println(add5(1));
}

public static int add5(int a) {
    return add5(a) + 5;
}

Un StackOverflowError básicamente es cuando intentas hacer algo, que probablemente se llama a sí mismo y continúa hasta el infinito (o hasta que da un StackOverflowError).

add5(a) se llamará a sí mismo y luego se llamará a sí mismo de nuevo, y así sucesivamente.

¿Qué es un StackOverflowError , qué lo causa y cómo debo tratar con ellos?


Como dices, necesitas mostrar algún código. :-)

Un error de desbordamiento de pila usualmente ocurre cuando su función llama al nido demasiado profundamente. Consulte el hilo del Código de desbordamiento de pila para ver algunos ejemplos de cómo sucede esto (aunque en el caso de esa pregunta, las respuestas provocan el desbordamiento de la pila).


El término "desbordamiento de pila (desbordamiento)" se usa a menudo, pero es un nombre inapropiado; los ataques no desbordan la pila sino que almacenan buffers en la pila.

- de las diapositivas del profesor Dr. Dieter Gollmann


Este es un caso típico de java.lang.Error ... El método se llama a sí mismo recursivamente sin salida en doubleValue() , floatValue() , etc.

Rational.java

    public class Rational extends Number implements Comparable<Rational> {
        private int num;
        private int denom;

        public Rational(int num, int denom) {
            this.num = num;
            this.denom = denom;
        }

        public int compareTo(Rational r) {
            if ((num / denom) - (r.num / r.denom) > 0) {
                return +1;
            } else if ((num / denom) - (r.num / r.denom) < 0) {
                return -1;
            }
            return 0;
        }

        public Rational add(Rational r) {
            return new Rational(num + r.num, denom + r.denom);
        }

        public Rational sub(Rational r) {
            return new Rational(num - r.num, denom - r.denom);
        }

        public Rational mul(Rational r) {
            return new Rational(num * r.num, denom * r.denom);
        }

        public Rational div(Rational r) {
            return new Rational(num * r.denom, denom * r.num);
        }

        public int gcd(Rational r) {
            int i = 1;
            while (i != 0) {
                i = denom % r.denom;
                denom = r.denom;
                r.denom = i;
            }
            return denom;
        }

        public String toString() {
            String a = num + "/" + denom;
            return a;
        }

        public double doubleValue() {
            return (double) doubleValue();
        }

        public float floatValue() {
            return (float) floatValue();
        }

        public int intValue() {
            return (int) intValue();
        }

        public long longValue() {
            return (long) longValue();
        }
    }

Main.java

    public class Main {

        public static void main(String[] args) {

            Rational a = new Rational(2, 4);
            Rational b = new Rational(2, 6);

            System.out.println(a + " + " + b + " = " + a.add(b));
            System.out.println(a + " - " + b + " = " + a.sub(b));
            System.out.println(a + " * " + b + " = " + a.mul(b));
            System.out.println(a + " / " + b + " = " + a.div(b));

            Rational[] arr = {new Rational(7, 1), new Rational(6, 1),
                    new Rational(5, 1), new Rational(4, 1),
                    new Rational(3, 1), new Rational(2, 1),
                    new Rational(1, 1), new Rational(1, 2),
                    new Rational(1, 3), new Rational(1, 4),
                    new Rational(1, 5), new Rational(1, 6),
                    new Rational(1, 7), new Rational(1, 8),
                    new Rational(1, 9), new Rational(0, 1)};

            selectSort(arr);

            for (int i = 0; i < arr.length - 1; ++i) {
                if (arr[i].compareTo(arr[i + 1]) > 0) {
                    System.exit(1);
                }
            }


            Number n = new Rational(3, 2);

            System.out.println(n.doubleValue());
            System.out.println(n.floatValue());
            System.out.println(n.intValue());
            System.out.println(n.longValue());
        }

        public static <T extends Comparable<? super T>> void selectSort(T[] array) {

            T temp;
            int mini;

            for (int i = 0; i < array.length - 1; ++i) {

                mini = i;

                for (int j = i + 1; j < array.length; ++j) {
                    if (array[j].compareTo(array[mini]) < 0) {
                        mini = j;
                    }
                }

                if (i != mini) {
                    temp = array[i];
                    array[i] = array[mini];
                    array[mini] = temp;
                }
            }
        }
    }

Resultado

    2/4 + 2/6 = 4/10
    Exception in thread "main" java.lang.Error
    2/4 - 2/6 = 0/-2
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
    2/4 * 2/6 = 4/24
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
    2/4 / 2/6 = 12/8
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
        at com.xetrasu.Rational.doubleValue(Rational.java:64)
        at com.xetrasu.Rational.doubleValue(Rational.java:64)

Aquí está el código fuente de Error en OpenJDK 7


La causa más común de desbordamientos de pila es una recursión excesivamente profunda o infinita . Si este es su problema, este tutorial sobre Java Recursion podría ayudar a entender el problema.


Los parámetros y las variables locales se asignan en la pila (con tipos de referencia, el objeto vive en el montón y una variable hace referencia a ese objeto). La pila normalmente 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, hay un potencial para que el montón "choque" con la pila (¡¡un poco como las placas tectónicas !!!).

La causa común de un desbordamiento de pila es una llamada recursiva incorrecta . Normalmente, esto se produce cuando las funciones recursivas no tienen la condición de terminación correcta, por lo que termina llamándose a sí misma para siempre.

Sin embargo, con la programación GUI, es posible generar recursión indirecta . Por ejemplo, su aplicación puede manejar mensajes de pintura y, mientras los procesa, puede llamar a una función que hace que el sistema envíe otro mensaje de pintura. Aquí no te has llamado explícitamente a ti mismo, pero OS / VM lo ha hecho por ti.

Para lidiar con ellos, necesitarás examinar tu código. Si tiene funciones que se llaman a sí mismas, verifique que tenga una condición de terminación. Si lo ha hecho, entonces verifique que cuando llame a la función, al menos haya modificado uno de los argumentos, de lo contrario no habrá un cambio visible para la función llamada recursivamente y la condición de terminación es inútil.

Si no tiene funciones recursivas obvias, verifique si está llamando a alguna función de biblioteca que indirectamente hará que se llame a su función (como en el caso implícito anterior).


Si tienes una función como:

int foo()
{
    // more stuff
    foo();
}

Entonces foo () seguirá llamándose a sí mismo, cada vez más profundo, y cuando se llena el espacio utilizado para realizar un seguimiento de las funciones en las que está, se obtiene el error de desbordamiento de pila.


Un Error es un error de tiempo de ejecución en java.

Se lanza cuando se excede la cantidad de memoria de pila de llamadas asignada por JVM.

Un caso común de aa Error se lanza cuando la pila de llamadas excede debido a una excesiva recursión profunda o infinita.

Ejemplo:

public class Factorial {
    public static int factorial(int n){
        if(n == 1){
            return 1;
        }
        else{
            return n * factorial(n-1);
        }
    }

    public static void main(String[] args){
        System.out.println("Main method started");
        int result = Factorial.factorial(-1);
        System.out.println("Factorial ==>"+result);
        System.out.println("Main method ended");
    }
}

Rastreo de pila:

Main method started
Exception in thread "main" java.lang.Error
at com.program..Factorial.factorial(Factorial.java:9)
at com.program..Factorial.factorial(Factorial.java:9)
at com.program..Factorial.factorial(Factorial.java:9)

En el caso anterior se puede evitar hacer cambios programáticos. Pero si la lógica del programa es correcta y aún así ocurre, entonces se debe aumentar el tamaño de la pila.


Error es para la pila como OutOfMemoryError es para el montón.

Las llamadas recursivas no unidas provocan que el espacio de pila se agote.

El siguiente ejemplo produce Error :

class  Demo
{
    public static void unboundedRecursiveCall() {
     unboundedRecursiveCall();
    }

    public static void main(String[] args) 
    {
        unboundedRecursiveCall();
    }
}

Error se puede evitar si las llamadas recursivas están limitadas para evitar que el total agregado de llamadas incompletas en memoria (en bytes) exceda el tamaño de pila (en bytes).





stack-overflow