此问题基于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;会发生什么?堆栈中的内存多于可以使用的内容?
答案 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上,它被称为访问冲突。如果您不那么幸运,它会破坏您的计划数据,并且您将在以后找不到。