运行时堆栈溢出

4

如果编译器在运行前计算了所需堆栈的大小,那么堆栈溢出是如何发生的呢?编译器是否会在编译时计算整个程序所需的堆栈总内存量?


编译器的计算过程中可能会出现堆栈溢出。我认为典型的编译器不会进行这种计算。 - MikeCAT
1
计算机只有那么多的“堆栈空间”。如果由于某种原因(无限递归,越界访问数组,其他未定义行为)在程序中使用了超过该空间的空间,则会发生堆栈溢出。 - NathanOliver
如果编译器在运行时之前计算所需的堆栈大小,除了最简单的情况外,它实际上无法做到这一点。 - drescherjm
编译器不会计算堆栈的大小,为什么要这样做呢?可用堆栈内存的大小可能会在一次运行和另一次运行之间发生变化。 - Yksisarvinen
3
“如果我的假设正确,为什么事实与我的假设相矛盾?”这个问题的答案通常是假设是错误的。 - molbdnilo
显示剩余3条评论
3个回答

6

不行。

编译器只能在非常有限的程度上了解运行时发生的情况。例如,它无法判断执行以下函数所需的栈大小:

void foo() {
    int x = 0;
    std::cin >> x;
    if (x == 42) foo();
}

栈是一种有限资源,如果超过了它的极限,就会出现栈溢出(stackoverflow)。


我的问题是,针对这些异常情况是否有预防措施?也许可以分配到堆中? - Streamline Astra
1
@StreamlineAstra 但是,通常情况下你无法确定哪些函数以何种顺序被调用,因此你无法防止堆栈溢出。理论上来说,你可以做到,但由未知事件决定的程序流程会使其变得困难。 - Ted Klein Bergman

5
考虑这个非常简化的示例函数(伪代码):
 void Foobar(long nested) {
    if( --nested >= 0)
        Foobar(nested);
 }

每次调用都会将(至少)返回地址推入堆栈。

问题:你需要多少内存?

确切地说,这就是原因。


3
编译器通常可以知道每个函数所需的堆栈内存大小,但编译时无法知道哪些函数将被调用。因此,可能会出现超出堆栈内存的函数调用堆栈。
此外,堆栈内存可以在进程或线程之间更改,因此编译器不知道编译时的限制。
最后,您可以在堆栈上动态分配内存。这是通过递归或使用C中的alloca等调用完成的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接