当确定使用的c ++程序堆栈大小?

我知道链接上的最大堆栈大小通常是固定的(也许是在Windows上)。

但我不知道何时使用的程序堆栈大小(不是最大堆栈大小)使用的是固定到OS。 编译? 联系? 执行 ?

像这样:

int main(){ int a[10]; return 0;} 

该程序只使用10 * sizeof(int)堆栈。 那么,堆栈大小是固定的吗?

首先。 如果在malloc或free时更改堆大小?

加载程序时,未向OS显式提供堆栈大小。 相反,OS使用页面错误机制(如果MMU支持它)。

如果您尝试访问尚未由操作系统授予的内存,MMU会生成由OS处理的页面错误。 操作系统检查页面错误的地址,并通过创建新的内存页面扩展堆栈,或者如果堆栈限制已用尽,则将其作为堆栈溢出处理。

考虑在x86和Linux上运行以下程序:

 void foo(void) { volatile int a = 10; foo(); } int main() { foo(); } 

由于无限递归和堆栈溢出,它会出错。 它实际上需要完成无限堆栈。 加载程序时,OS分配初始堆栈并将其写入%rsp (堆栈指针)。 我们来看看foo()反汇编:

 push %rbp mov %rsp,%rbp <--- Save stackpointer to %rbp sub $0x10,%rsp <--- Advance stack pointer by 16 bytes movl $0xa,-0x4(%rbp) <--- Write memory at %rbp callq 0x400500  leaveq retq 

在最多4096/16 = 256次调用foo() ,您将通过在地址X + 4096处写入内存来中断页边界,其中X是初始%rsp值。 然后将生成页面错误,OS为堆栈提供新的内存页面,允许程序使用它。

在大约500k的foo()调用(对于堆栈的默认Linux ulimit)之后,操作系统将检测到该应用程序使用了太多堆栈页面并向其发送SIGSEGV。

在回答问题时,我提供了以下信息:

BSS / DATA段包含所有全局变量,默认情况下初始化为特定值或零。 该段是可执行映像的一部分。 在加载时,堆段被添加到此; 但是,它不是“段”,而只是作为加载的BSS / DATA段的扩展而分配的额外数据量。 以相同的方式,堆栈“段”不是真正的段,而是添加到BSS +堆段。 堆栈增长而堆增长。 如果这些重叠(使用更多堆并且堆栈仍在增长)发生“内存不足”错误(堆)或“堆栈溢出”(堆栈) – 这可以通过使用段寄存器(Intel)来触发硬件生成例外或使用软件检查。

这是布局细分的传统方式。 想想旧的英特尔芯片,其中所有的progeram数据必须是64KB。 对于更现代的芯片,通常使用相同的布局,其中在该布局中使用32MB的地址空间但仅使用所需的实际物理存储器。 因此堆栈可能非常大。