当您请求堆栈中的空间多于可用空间时会发生什么?

时间:2015-11-05 15:55:39

标签: c++ stack heap

此问题基于C / C ++内存分配。

我读到了堆栈和堆之间的差异,有一件事让我感到困惑。应该在堆中为大对象分配内存,但是也可以在堆栈中将其作为局部变量来实现。

从这个帖子(C/C++ maximum stack size of program)我明白堆栈是有限的,限制相对较低(最多7.4MB)。

我使用以下程序测试了此限制:

#include <vector> 
int main() {
std::vector<double> test;

for (int i = 0; i < 5000000; i++){
    test.push_back(i);
}

return 0;
}

总分配内存为8字节*(5.000.000)= 40MByte。 这似乎不会引起任何错误。我读了这个资源(https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors),堆栈溢出可能会引发分段错误或总线错误。

所以我想,问题是:当你&#34;分配&#34;会发生什么?堆栈中的内存多于可以使用的内容?

2 个答案:

答案 0 :(得分:0)

堆栈溢出的行为取决于平台。官方术语可能是&#34;未定义的行为&#34; ,这意味着任何事情都可能发生。

平台不需要实现堆栈,尽管这是一种常见的技术。

有些平台为堆栈和堆都预留了内存,并让它们“生长”#34;彼此相对(画一幅画)。因此,如果堆栈溢出,它将开始在堆上写入,反之亦然。

某些平台可能设置了硬件围栏,当处理器访问超出范围的内存时,会生成硬件异常。操作系统会处理该异常。

另一个例子是您的程序开始写入某种硬件设备,例如USB控制器或磁盘驱动器控制器。

总之, Stack Overflow 的行为取决于平台,包括恢复(如果有)。

答案 1 :(得分:0)

std::vector在堆上分配内存,而不是堆栈。如果您想测试大头钉分配,最简单的方法是使用如下程序:

#include <cstdio>
int main(void) {
    char temp[1024*1024*40] = {};
    printf("%s\n",temp);
    return 0;
}

(注意打印是必要的,以防止缓冲区被优化掉。)
这在堆栈上分配40 MiB,并产生堆栈溢出(见live)。

另一种方法是递归调用函数。例如:

unsigned factorial_times_2(unsigned n) {
    unsigned result;

    if (n<2u) result=1u;
    result = n * (factorial_times_2(n-1u)/2u);

    return result * 2u;
}
int main(void) {
    return factorial_times_2(~0u)/2u;
}

这是对经典递归因子函数的简单修改(修改后,因为现代编译器将使简单因子尾递归)。在运行时,它将尝试生成大约40亿个堆栈帧。产生堆栈溢出(参见live)。

如您所料,堆栈溢出意味着您超出了给堆栈的内存。由于堆栈通常被分配了自己的页面,因此走出堆栈会走出有效的映射内存地址。

因此,堆栈溢出通常会导致分段错误(如上例所示)。在Windows上,它被称为访问冲突。如果您不那么幸运,它会破坏您的计划数据,并且您将在以后找不到。