当前位置:  开发笔记 > 编程语言 > 正文

什么是StackOverflowError?

如何解决《什么是StackOverflowError?》经验,为你挑选了8个好方法。

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



1> Sean..:

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

您的进程还有一个,它位于流程的底端.在分配内存时,此堆可以向地址空间的上端增长.正如您所看到的,堆有可能与堆栈"碰撞"(有点像构造板块!!!).

堆栈溢出的常见原因是错误的递归调用.通常,这是在递归函数没有正确的终止条件时引起的,因此最终会自动调用它自己.

但是,使用GUI编程,可以生成间接递归.例如,您的应用程序可能正在处理绘制消息,并且在处理它们时,它可能会调用一个函数,使系统发送另一个绘制消息.在这里你没有明确地称呼自己,但OS/VM已经为你完成了.

要处理它们,您需要检查代码.如果你有自己调用的函数,那么检查你是否有终止条件.如果你有,那么检查一下,在调用函数时你至少修改了一个参数,否则递归调用的函数没有明显的变化,终止条件也没用.

如果你没有明显的递归函数,那么检查你是否正在调用任何间接导致函数被调用的库函数(如上面的隐含情况).


应该指出的是,"几乎*"不可能"处理"堆栈溢出错误.在大多数环境中,要处理错误,需要在堆栈上运行代码,如果没有更多的堆栈空间,这很难.
哈哈哈,所以这里是:while(points <100){addMouseListeners(); moveball(); checkforcollision(); 暂停(速度);}哇我没有意识到我会最终得到一堆鼠标听众感到羞耻...谢谢你们!
不,如果您在http://en.wikipedia.org/wiki/Stack_overflow上查找维基百科上的文章,堆栈溢出也可能来自变量太大而无法在堆栈上分配.
@JB King:不适用于Java,只有原始类型和引用保留在堆栈中.所有重要的东西(数组和对象)都在堆上.

2> Varun..:

为了描述这一点,首先让我们了解局部变量和对象是如何存储的.

局部变量存储在堆栈中: 在此输入图像描述

如果您查看图像,您应该能够理解事物是如何工作的.

当Java应用程序调用函数调用时,会在调用堆栈上分配堆栈帧.堆栈帧包含调用方法的参数,其本地参数以及方法的返回地址.返回地址表示执行点,程序执行将在调用方法返回后继续执行.如果没有新堆栈帧的空间,StackOverflowError则由Java虚拟机(JVM)抛出.

可能耗尽Java应用程序堆栈的最常见情况是递归.在递归中,方法在执行期间调用自身.递归被认为是一种强大的通用编程技术,但必须谨慎使用,以避免StackOverflowError.

投掷a的示例StackOverflowError如下所示:

StackOverflowErrorExample.java:

public class StackOverflowErrorExample {

    public static void recursivePrint(int num) {
        System.out.println("Number: " + num);

        if(num == 0)
            return;
        else
            recursivePrint(++num);
    }

    public static void main(String[] args) {
        StackOverflowErrorExample.recursivePrint(1);
    }
}

在这个例子中,我们定义了一个递归方法,调用recursivePrint它打印一个整数,然后调用自身,下一个连续的整数作为参数.递归结束,直到我们0作为参数传入.但是,在我们的示例中,我们从1传递参数及其增加的关注者,因此递归永远不会终止.

使用-Xss1M指定线程堆栈大小等于1MB 的标志的示例执行如下所示:

Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
        at java.io.PrintStream.write(PrintStream.java:480)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
        at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
        at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
        at java.io.PrintStream.write(PrintStream.java:527)
        at java.io.PrintStream.print(PrintStream.java:669)
        at java.io.PrintStream.println(PrintStream.java:806)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        ...

根据JVM的初始配置,结果可能会有所不同,但最终StackOverflowError会抛出.这个例子是递归如何导致问题的一个非常好的例子,如果没有谨慎实施的话.

如何处理StackOverflowError

    最简单的解决方案是仔细检查堆栈跟踪并检测行号的重复模式.这些行号表示递归调用的代码.一旦检测到这些行,就必须仔细检查代码并理解递归永不终止的原因.

    如果您已验证正确实现了递归,则可以增加堆栈的大小,以便允许更多的调用.根据安装的Java虚拟机(JVM),默认线程堆栈大小可能等于512KB或1MB.您可以使用-Xss标志增加线程堆栈大小.可以通过项目的配置或命令行指定此标志.-Xss参数的格式 是: -Xss[g|G|m|M|k|K]



3> Khoth..:

如果你有这样的功能:

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

然后foo()将继续调用自身,越来越深,当用于跟踪你所处的函数的空间被填满时,你会得到堆栈溢出错误.


错误.你的函数是尾递归的.大多数编译语言都有尾递归优化.这意味着递归会简化为一个简单的循环,并且在某些系统上,您永远不会遇到这段代码的堆栈溢出.

4> Cheery..:

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

如果堆栈为空,则无法弹出,如果这样,您将遇到堆栈下溢错误.

如果堆栈已满,则无法推送,如果这样,您将收到堆栈溢出错误.

因此,堆栈溢出会出现在堆栈中分配太多的地方.例如,在上面提到的递归中.

一些实现优化了某些形式的递归.特别是尾递归.尾递归例程是例程的形式,其中递归调用作为例程的最终事件出现.这种常规调用简单地简化为跳转.

有些实现甚至可以实现自己的递归堆栈,因此它们允许递归继续,直到系统内存不足.

如果可以的话,你可以尝试的最简单的事情是增加堆栈大小.如果你不能这样做,那么第二个最好的事情是看是否有明显导致堆栈溢出的东西.通过在调用例程之前和之后打印一些东西来尝试它.这有助于您找出失败的例程.


堆栈中可能出现堆栈下溢(弹出比你推送的更多),但在编译语言中它几乎是不可能的.我不确定,您可能能够找到C的alloca()的实现,它"支持"负的大小.
是否存在堆栈*下溢*?
堆栈溢出意味着:堆栈溢出.通常有程序中的一个堆栈包含本地范围变量 - >不行,每个线程都有自己的堆栈,它包含了含有局部变量的每个方法调用堆栈帧..

5> Greg..:

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



6> Chris Jester..:

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

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



7> splattne..:

堆栈溢出的最常见原因是过深或无限递归.如果这是您的问题,那么关于Java Recursion的本教程可以帮助您理解该问题.



8> Vikram..:

StackOverflowError是堆栈OutOfMemoryError的堆栈.

无限递归调用导致堆栈空间用完.

以下示例生成StackOverflowError:

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

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

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

推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有