Memory leaks 什么是堆栈溢出错误?

Memory leaks 什么是堆栈溢出错误?,memory-leaks,exception-handling,out-of-memory,stack-overflow,Memory Leaks,Exception Handling,Out Of Memory,Stack Overflow,什么是StackOverflower错误,是什么导致的,我应该如何处理它们?就像你说的,你需要展示一些代码。:-) 当函数调用嵌套太深时,通常会发生堆栈溢出错误。请参阅线程以了解如何发生这种情况的一些示例(尽管在该问题中,答案故意导致堆栈溢出)。堆栈溢出通常是通过嵌套太深的函数调用来调用的(使用递归时尤其容易,即调用自身的函数)或者在堆栈上分配大量内存,使用堆会更合适。如果您有如下功能: int foo() { // more stuff foo(); } 然后foo()会不断

什么是StackOverflower错误,是什么导致的,我应该如何处理它们?

就像你说的,你需要展示一些代码。:-)


当函数调用嵌套太深时,通常会发生堆栈溢出错误。请参阅线程以了解如何发生这种情况的一些示例(尽管在该问题中,答案故意导致堆栈溢出)。

堆栈溢出通常是通过嵌套太深的函数调用来调用的(使用递归时尤其容易,即调用自身的函数)或者在堆栈上分配大量内存,使用堆会更合适。

如果您有如下功能:

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

然后foo()会不断地调用自己,越来越深,当用来跟踪所使用函数的空间被填满时,就会出现堆栈溢出错误。

参数和局部变量在堆栈上分配(对于引用类型,对象位于堆上,堆栈中的一个变量引用堆上的该对象)。堆栈通常位于地址空间的上端,当它用完时,它朝向地址空间的底部(即接近零)

public class Example3 {

public static void main(String[] args) {

    main(new String[1]);

}
您的进程也有一个堆,它位于进程的底部端。分配内存时,这个堆可能会向地址空间的上端增长。正如您所看到的,堆有可能与堆栈发生碰撞(有点像板块!!!)

堆栈溢出的常见原因是错误的递归调用。通常,这是由于递归函数没有正确的终止条件而导致的,因此它最终会永远调用自己。或者,当终止条件良好时,可能是由于在执行之前需要太多的递归调用

但是,通过GUI编程,可以生成间接递归。例如,您的应用程序可能正在处理绘制消息,并且在处理这些消息时,它可能会调用一个函数,导致系统发送另一条绘制消息。在这里,您没有显式调用自己,但OS/VM已经为您完成了此操作

要处理这些问题,您需要检查代码。如果有调用自己的函数,请检查是否有终止条件。如果有,请检查在调用函数时是否至少修改了一个参数,否则递归调用的函数和终止条件将不会有可见的更改终止条件是无用的。还要注意,在达到有效终止条件之前,堆栈空间可能会耗尽内存,因此请确保您的方法可以处理需要更多递归调用的输入值


如果没有明显的递归函数,请检查是否调用了间接地将导致调用函数的库函数(如上面的隐式情况).

导致堆栈溢出的最常见原因是过深或无限递归。如果这是您的问题,可以帮助您理解问题。

堆栈溢出的确切含义是:堆栈溢出。通常程序中只有一个堆栈,其中包含局部范围变量和执行时返回的地址例程的初始化结束。堆栈往往是内存中某个位置的固定内存范围,因此它可以包含的值有限

如果堆栈为空,则无法弹出,否则将出现堆栈下溢错误

public class Example3 {

public static void main(String[] args) {

    main(new String[1]);

}
如果堆栈已满,则无法推送,否则将出现堆栈溢出错误

public class Example3 {

public static void main(String[] args) {

    main(new String[1]);

}
因此,当您在堆栈中分配太多时,就会出现堆栈溢出。例如,在前面提到的递归中

一些实现优化了某些形式的递归。特别是尾部递归。尾部递归例程是一种例程形式,其中递归调用作为例程所做的最后一件事出现。这样的例程调用被简化为跳转

有些实现甚至实现了自己的递归堆栈,因此它们允许递归继续,直到系统内存耗尽


如果可以,您可以尝试的最简单的方法是增加堆栈大小。但是,如果您不能这样做,第二个最好的方法是查看是否存在明显导致堆栈溢出的原因。在调用例程之前和之后打印一些内容来尝试。这有助于您找出失败的例程。

StackOverflowError
OutOfMemoryError
与堆一样位于堆栈中

无界递归调用会导致堆栈空间被耗尽

以下示例生成
堆栈溢出错误

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

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

如果递归调用是有界的,以防止未完成的内存内调用(以字节为单位)的总和超过堆栈大小(以字节为单位),则可以避免堆栈溢出错误。

下面是一个递归算法的示例,用于反转单链接列表。在具有以下规范的笔记本电脑上(4G内存,Intel Core i5 2.3GHz CPU,64位Windows 7),对于大小接近10000的链表,此函数将遇到StackOverflow错误

我的观点是,我们应该明智地使用递归,始终考虑系统的规模。 通常,递归可以转换为迭代程序,该程序的伸缩性更好。(同一算法的一个迭代版本在页面底部给出,它在9毫秒内反转大小为100万的单链表。)

同一算法的迭代版本:

    public static LinkedListNode reverseIteratively(LinkedListNode head){
    return doReverseIteratively(null, head);
}   

private static LinkedListNode doReverseIteratively(LinkedListNode x, LinkedListNode first) {

    while (first != null) {
        LinkedListNode second = first.next;
        first.next = x;
        x = first;

        if (second == null) {
            break;
        } else {
            first = second;
        }
    }
    return first;
}


public static LinkedListNode reverseIteratively(LinkedListNode head){
    return doReverseIteratively(null, head);
}
术语“堆栈溢出(溢出)”经常被使用,但用词不当;攻击不会使堆栈溢出,而是使堆栈上的缓冲区溢出


--从

的课堂幻灯片中,为了描述这一点,首先让我们了解一下本地的
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");
    }
}
Main method started
Exception in thread "main" java.lang.StackOverflowError
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
    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();
        }
    }
    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;
                }
            }
        }
    }
    2/4 + 2/6 = 4/10
    Exception in thread "main" java.lang.StackOverflowError
    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)
public class Example3 {

public static void main(String[] args) {

    main(new String[1]);

}
class Human {
    Human(){
        new Animal();       
    }
}

class Animal extends Human {
    Animal(){
        super();
    }
}

public class Test01 {
    public static void main(String[] args) {
        new Animal();
    }
}