为什么不总是发生堆栈溢出?

时间:2014-07-28 13:00:22

标签: java memory stack-overflow

我目前正在学习Java,作为我学习的一部分,我试图故意引起堆栈溢出,看看它会做什么。

我做了一些边界测试,有趣的是,我发现如果我执行以下代码,它只会偶尔导致错误。有时它会毫无问题地运行。

public class SO
{
    public static void main(String[] args)
    {
        ohno(0);
    }

    public static void ohno(int a)
    {
        System.out.println(a);
        if (a != 11413)
            ohno(a+1);
    }
}

我的问题如下:

  • 可能导致我的堆栈大小在这个非常简单的示例的执行之间变化的原因是什么?
  • 现在,由于代码设计不当(即无限递归,过大的原语等),是否总是会发生堆栈溢出,或者是否存在堆栈仍然是技术限制的真实场景?
  • 这个看起来很明显,但是......增加系统的物理内存是否也增加了堆栈的大小?

3 个答案:

答案 0 :(得分:3)

有限的堆栈大小是您分配给JVM的内存量的函数。

资源受限的系统具有可以分配的更少内存,因此绝对存在堆栈大小受限制的实际场景,并且有时您必须自然地使用迭代解决方案 - 结果导致的错误问题。

增加系统的物理内存只对您允许JVM分配内存很重要,否则您将获得该平台的默认值。

答案 1 :(得分:1)

发生StackOverflowException的可能性取决于您分配的内存量,使用参数XmxM / G表示最大内存,XmxS / G表示最小内存。

堆栈溢出可能发生在任何情况下,如果存在死循环,或者有可能通过自动循环获得大量数据(这会消耗大量内存)的数据。

答案 2 :(得分:0)

许多编译器检测尾递归调用并为该调用重用相同的堆栈帧,从而防止此类调用增加堆栈。尾递归调用是递归调用是方法或函数中的最后一条指令的调用。此优化允许您使用尾递归而不必担心堆栈溢出。

如果希望引发溢出,请尝试在递归调用后添加一些代码以防止优化。您可能需要稍微玩一下 - 好的编译器很狡猾,可能会破坏简单的尝试。