什么是StackOverflowError,是什么原因导致的,我应该如何处理它们?


当前回答

如您所说,您需要展示一些代码。: -)

堆栈溢出错误通常发生在函数调用nest太深的时候。请参阅Stack Overflow Code Golf线程,以了解如何发生这种情况(尽管在这个问题的情况下,答案会故意导致堆栈溢出)。

其他回答

堆栈溢出的意思就是:堆栈溢出。通常在程序中有一个堆栈,它包含局部作用域变量和例程执行结束时返回的地址。该堆栈往往是内存中的某个固定内存范围,因此它可以包含多少值是有限的。

如果堆栈是空的,你不能弹出,如果你这样做,你会得到堆栈溢出错误。

如果堆栈满了,你就不能推,如果你推了,你就会得到堆栈溢出错误。

当你在堆栈中分配了太多内存时,就会出现堆栈溢出。例如,在前面提到的递归中。

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

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

你可以尝试的最简单的事情就是如果可以的话增加你的堆栈大小。如果不能这样做,那么第二种方法是查看是否有什么东西明显导致堆栈溢出。试着在调用前后打印一些东西到例程中。这可以帮助您找到失败的例程。

堆栈溢出最常见的原因是过于深入或无限递归。如果这是你的问题,这个关于Java递归的教程可以帮助你理解这个问题。

StackOverflowError是Java中的运行时错误。

当超过JVM分配的调用堆栈内存量时抛出该异常。

抛出StackOverflowError的一种常见情况是由于过度深度递归或无限递归而导致调用堆栈超出。

例子:

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)

在上述情况下,可以通过进行编程更改来避免这种情况。 但如果程序逻辑是正确的,它仍然发生,那么你的堆栈大小需要增加。

StackOverflowError之于堆栈,就像OutOfMemoryError之于堆。

无界递归调用会导致堆栈空间被用完。

产生StackOverflowError的示例如下:

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

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

如果对递归调用进行了限制,以防止内存中不完整调用的总和(以字节为单位)超过堆栈大小(以字节为单位),则可以避免StackOverflowError。

下面是一个递归算法的例子,用于反转单链表。在笔记本电脑(规格为4gb内存,Intel Core i5 2.3 GHz CPU 64位,Windows 7)上,对于大小接近10,000的链表,该函数将遇到StackOverflow错误。

我的观点是,我们应该明智地使用递归,始终考虑到系统的规模。

通常递归可以转换为迭代程序,迭代程序的伸缩性更好。(本页底部给出了同一算法的一个迭代版本。它在9毫秒内反转大小为100万的单链表。)

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

    LinkedListNode second = first.next;

    first.next = x;

    if(second != null){
        return doReverseRecursively(first, second);
    }else{
        return first;
    }
}


public static LinkedListNode reverseRecursively(LinkedListNode head){
    return doReverseRecursively(null, head);
}

同一算法的迭代版本:

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