【问题标题】:Stack size verification and StackOverflowError堆栈大小验证和 StackOverflowError
【发布时间】:2015-10-06 12:52:03
【问题描述】:

在Java中,每个线程都会分配一些由-Xss参数定义的堆栈内存,并且有一些默认值。

现在,我通过以java -Xss1k Test 运行以下代码来覆盖默认堆栈大小。

最后输出:

18479
18480Exception in thread "main" java.lang.StackOverflowError

问题:

  • 为什么要打印 18479 之前的值?我期望的值要少得多,因为我提到了 1KB 的堆栈大小,并且在每个堆栈帧上存储了一个 int。
  • 如果堆栈大小为 1KB 或 1024 字节,则只能存储 256 (1024/4) 个 int 值。不?因为每次递归调用都会添加一个堆栈帧,并将 int 存储在上面。因此,只要添加了 256 个每个大小为 4 字节的堆栈帧,就会出现 StackOverflowError。
  • 我的理解是全局作用域counter 不会以任何方式对堆栈消耗做出贡献,因为它将存在于旧代空间中。确认?


 public class Test {
    private static int counter = 0;
    public static void main(String[] args) {
        getMeStackOverflowException();
    }

    private static void getMeStackOverflowException(){
        int x = 123;
        System.out.println(Test.counter++);
        getMeStackOverflowException();
    }
}

【问题讨论】:

    标签: java stack stack-size


    【解决方案1】:

    如果堆栈大小为 1KB 或 1024 字节,则只能存储 256 (1024/4) 个 int 值。不?

    没有。返回地址也存储在堆栈中,因此您应该在少于 256 次递归调用中溢出。

    我的理解是全局作用域 x 不会以任何方式对堆栈消耗做出贡献,因为它将存在于旧代空间中。确认?

    已确认。

    对于 Windows:

    请注意,在某些版本的 Windows 上,操作系统可能会使用非常粗略的粒度对线程堆栈大小进行四舍五入。如果请求的大小比默认大小小 1K 或更多,则堆栈大小向上舍入到默认值;否则,堆栈大小将向上舍入为 1 MB 的倍数

    Source.

    【讨论】:

    • 对不起,我加了一点。我真的很想知道为什么要打印 18479 之前的值。我期望的值要少得多,因为我提到了 1KB 的堆栈大小并且在每个堆栈帧上存储了一个 int。
    • "返回地址也存储在堆栈中" 最后一个方法堆栈帧的返回地址是哪个?能详细点吗??
    • "你应该在少于 256 次递归调用中溢出。"是的,但它没有,这就是我无法理解的原因。
    • 当任何方法被调用时,当前方法的resume-at地址连同在栈上传递的任何参数一起被放入栈中。当新方法获得控制权时,它会进一步扩展堆栈以创建任何局部变量。所有这些都假设没有 JIT 优化,例如方法内联或在寄存器中传递参数/将局部变量分配给寄存器。至于为什么会得到如此大的输出,在某些 Java 版本中一直存在 -Xss 被忽略的历史。参见例如stackoverflow.com/q/21404616/141172。也许这适用于您的情况。
    • 即使它采用 64KB 的默认大小(我使用的是 Windows 7),也采用 64*1024=65536 字节的堆栈大小。现在,4 个字节的 int 和 1 个字节的内存地址意味着 5 个字节,所以最大迭代应该是 ~13107。但我得到了 18480。
    猜你喜欢
    • 2021-12-15
    • 2014-03-09
    • 2020-09-12
    • 2017-09-30
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多