为什么递归函数在随机数上停止?

Aft*_*360 12 java recursion

我编写了一个如下所示的小程序,该程序计算无限递归循环在导致StackOverflow错误之前将经过多少次。

public class Testing {
    static void p(int i) {
        System.out.println("hello" + i);
        i++;
        p(i);
    }
    public static void main(String[] args) {
        p(1);
    }
}
Run Code Online (Sandbox Code Playgroud)

事实是,它每次都会以不同的数字出错,通常在8000到9000之间。有人能解释为什么会这样吗?

编辑:我正在使用Eclipse IDE,尚未与其他IDE或命令行对其进行测试。

VHS*_*VHS 7

JVM规范很好地解释了其与堆栈有关的行为。

每个Java虚拟机线程都有一个私有Java虚拟机堆栈,与该线程同时创建。Java虚拟机堆栈存储框架(第2.6节)。Java虚拟机堆栈类似于常规语言(例如C)的堆栈:它保存局部变量和部分结果,并在方法调用和返回中起作用。因为除了推送和弹出帧外,从不直接操纵Java虚拟机堆栈,所以可以为堆分配帧。Java虚拟机堆栈的内存不必是连续的。

在Java®虚拟机规范的第一版中,Java虚拟机堆栈称为Java堆栈。

该规范允许Java虚拟机堆栈具有固定大小,或根据计算要求动态扩展和收缩。如果Java虚拟机堆栈的大小固定,则在创建每个Java虚拟机堆栈时可以独立选择它们的大小。

Java虚拟机实现可以为程序员或用户提供对Java虚拟机堆栈的初始大小的控制,并且在动态扩展或收缩Java虚拟机堆栈的情况下,可以控制最大和最小大小。

以下异常条件与Java虚拟机堆栈相关:

如果线程中的计算需要比允许的Java虚拟机更大的堆栈,则Java虚拟机将引发StackOverflowError。

如果可以动态扩展Java虚拟机堆栈,并尝试进行扩展,但是可以提供足够的内存来实现扩展,或者如果没有足够的内存来为新线程创建初始Java虚拟机堆栈,则Java虚拟机机器抛出OutOfMemoryError。

就您的问题而言,摘录中的重要一点:

  • 该规范允许Java虚拟机堆栈具有固定大小,或根据计算要求动态扩展和收缩。

由于未提供堆栈大小,因此,JVM会以递归方式调用该函数,从而需要更多堆栈内存,从而尝试动态扩展堆栈大小。在每次运行中,它可能会为其堆栈找到不同数量的动态内存,具体取决于运行时计算机上内存的可用性。这就是为什么您在抛出SO错误之前看到的迭代次数值会有所不同的原因。如果为程序配置(使用Xss<size>JVM参数)较小的堆栈,则应该在SO错误之前看到几乎相同数量的递归。