2015-11-05 92 views
-1

这个问题是基于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),发现堆栈溢出可能会引发分段错误或总线错误。

所以我想,问题是:当你在堆栈中“分配”更多的内存时会发生什么情况?

+6

DR; TL;它发生**堆栈溢出** – 101010

+1

'std :: vector'可能会将内存分配给堆,而不是堆栈。 – MikeCAT

+8

您不在测试堆栈分配,您正在测试堆分配。要测试堆栈分配,例如运行无限递归函数 - 您将得到本地错误的名称 – Rostislav

回答

0

std::vector在堆上分配内存,而不是堆栈。如果你想测试粘性分配,最简单的方法是使用一个程序,如:

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

(NB印刷是必要的,以防止缓冲区被优化掉。)
这对分配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上,它被称为访问冲突。如果你不那么幸运,它会破坏你的程序数据,直到以后你才会发现。

0

溢出堆栈的行为与平台有关。官方条款可能是“未定义的行为”,意思是任何事情都可能发生。

平台不需要实现堆栈,尽管这是一种常用技术。一些平台为栈和堆设置了存储器,并使它们彼此“成长”(绘制图片)。所以如果堆栈溢出,它就开始在堆上写,反之亦然。

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

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

总之,堆栈溢出的行为是平台相关的,包括恢复(如果有的话)。

相关问题