我知道最大堆栈大小通常在链接上是固定的(也许在 Windows 上就是这样)。
但我不知道所使用的程序堆栈大小(不是最大堆栈大小,只是使用的大小)何时固定到操作系统。编译?链接?执行?
像这样:
int main(){ int a[10]; return 0;}
该程序仅使用 10 * sizeof(int) 堆栈。那么,堆栈大小是固定的吗?
最重要的是。 malloc 或 free 时堆大小是否发生变化?
最佳答案
加载程序时,堆栈大小未明确提供给操作系统。相反,操作系统使用 page faults 机制(如果MMU支持的话)。
如果您尝试访问操作系统尚未授予的内存,MMU 会生成一个页面错误,该错误由操作系统处理。操作系统检查页面错误的地址,并通过创建新的内存页面来扩展堆栈,或者如果您已耗尽堆栈限制,则将其作为堆栈溢出进行处理。
考虑以下在 x86 和 Linux 上运行的程序:
void foo(void) {
volatile int a = 10;
foo();
}
int main() {
foo();
}
由于无限递归和堆栈溢出而导致错误。它实际上需要无限堆栈才能完成。当程序加载时,操作系统分配初始堆栈并将其写入%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 <foo>
leaveq
retq
在最多 4096/16 = 256 次 foo()
调用之后,您将通过在地址 X + 4096
处写入内存来打破页边界,其中 X 是初始值 %rsp
值。然后就会产生页面错误,操作系统为堆栈提供新的内存页面,允许程序使用它。
在大约 500k 次 foo()
调用(默认的 Linux ulimit 堆栈)之后,操作系统将检测到应用程序使用了过多的堆栈页面并向其发送 SIGSEGV。
关于c++ - 使用的C++程序堆栈大小何时确定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29960754/