gpt4 book ai didi

java - 多个递归方法调用的各种堆栈大小

转载 作者:行者123 更新时间:2023-12-01 13:39:34 24 4
gpt4 key购买 nike

在实验过程中,我发现了与堆栈溢出错误相关的非常有趣的问题。看一下这段代码:

Foo 类:

public class Foo {

private int i;

public void doFoo() {
i++;
doBar();
}

public void doBar() {
doFoo();
}

public int getI() {
return i;
}

public void reset() {
i = 0;
}
}

应用程序类别:

public class App {

public static void main(String[] args) {
Foo foo = new Foo();
try {
foo.doFoo();
} catch (StackOverflowError e) {
System.out.println(foo.getI());
}
}
}

很明显,递归调用doFoo和doBar方法会导致stackOverflowError。但是此后 foo.i 会有什么值呢?我已经使用默认虚拟机堆栈大小对其进行了几次测试 - 这就是 System.out.println(foo.getI());打印:

  • 第一次运行:4372
  • 第二次运行:8364
  • 第三次运行:3381
  • 第四次运行:8406
  • 第五次运行:3485

你能看到吗?持续运行此应用程序,i 变量将始终比上次运行大/小约 4500。

如果我们增加堆栈大小怎么办?添加时-Xss1m参数到VM args,结果如下:

  • 第一次运行:33364
  • 第二次运行:38404
  • 第三次运行:33787
  • 第四次运行:38434
  • 第五次运行:33805

都是一样的! i 值仍然比上次运行大/小约 4500!

然而,当我们将 main 方法更改为:

for (int i = 0; i < 10; i++) {
try {
foo.doFoo();
foo.reset();
} catch (StackOverflowError e) {
System.out.println(foo.getI());
}
}

我们将得到可预测的结果:

  • 38398
  • 80796
  • 123194
  • 165592
  • 207990
  • 250388
  • 292786
  • 335184
  • 377582
  • 419980

可能是由于JVM初始化后堆栈空闲空间越来越多。但是,为什么一次又一次地调用程序时会出现约 4500 次振荡呢?附言。我直接从 Eclipse 运行这个应用程序(如果重要的话)。

====

编辑:

好的,我现在可以看到,foo.reset()永远不会被调用,因为 Error 在它之前被抛出。当foo.dooFoo()foo.reset() 交换,我们现在有了恒定的结果:

  • 38394
  • 42394
  • 42394
  • 42394
  • 42394
  • 42394
  • 42394
  • 42394
  • 42394
  • 42394

但是,问题是为什么在运行程序时有大约 4500 次振荡,仍然是开放的。

==编辑2

此问题仅与直接从 Eclipse 运行(不带 -Xint 参数)有关。当程序从命令行启动时,java -cp . App ,i 更恒定:+/- 5。

最佳答案

我怀疑正在发生的事情(以及你的证据表明)是这些方法被频繁调用,以至于你的代码最终通过 JIT 编译器运行。当这种情况发生时,我推测优化可能会启动并认识到每次执行 doFoo 时递增 i 是不必要的——有点像展开循环.

我不完全确定为什么您会看到任何变化,除了 JIT 启动时可能存在不确定的成本组件,或者偶尔会启动几帧。

关于java - 多个递归方法调用的各种堆栈大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20937907/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com