我注意到每个正在运行的C程序都有一个名为[stack]的私有映射,它最初非常小(在我的机器上为128k),但会增长以适应任何自动变量(最大为堆栈大小限制)。我假设这是我的程序的调用堆栈所在的位置。
然而,它似乎并没有缩小到原来的大小。有没有办法在不终止进程的情况下释放内存?
如何在内部实现C堆栈;是什么增加了[堆栈]按需映射的大小?有些编译器生成代码,C库或操作系统?增加的触发点在哪里?
更新:我在x86-64上使用Linux 3.0.0,gcc 4.6.1和glibc6;因为这可能是非常具体的实现,任何有关它如何工作的信息都可以。
答案 0 :(得分:6)
这是特定于实现的,但我知道没有常用的平台可以缩小已提交的堆栈内存。堆栈按需增长是很常见的,但是一旦提交空间就会保持承诺。
答案 1 :(得分:3)
我相信Linux内核正在增长堆栈段(仅适用于主线程)。它不在编译器中(除了通过在调用时递增堆栈指针,忽略最近GCC的实验-fsplit-stack
选项),而不是在libC中。
如果您确定您的堆栈已经变得太大而且您不需要它,那么您可能会munmap
未使用的部分(但要小心;内核开发人员不会这么想,所以它可能不会按照预期工作;在1990年代早期,我记得曾在Sparc上使用这些肮脏的技巧破坏了SunOS5.0。
在Linux,x86-64上,有一台不错的机器,你真的不应该在乎。堆栈不是那么大......
我猜是堆栈段是mmap
- 用MAP_NORESERVE
MAP_STACK
MAP_GROWSDOWN
编辑,但我可能错了。
答案 2 :(得分:1)
在Linux / MMU中(在!MMU中你无法增加堆栈),堆栈会在页面错误处理程序中生成。对于x86,是否增加堆栈由以下arch/x86/mm/fault.c:do_page_fault()
的代码决定:
if (error_code & PF_USER) {
/*
* Accessing the stack below %sp is always a bug.
* The large cushion allows instructions like enter
* and pusha to work. ("enter $65535, $31" pushes
* 32 pointers and then decrements %sp by 65535.)
*/
if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
bad_area(regs, error_code, address);
return;
}
}
if (unlikely(expand_stack(vma, address))) {
bad_area(regs, error_code, address);
return;
}
expand_stack()
检查通常的RLIMITS(RLIMIT_AS,RLIMIT_STACK,RLIMIT_MEMLOCK),LSM是否允许增加堆栈,是否有过多的过度使用等等,最后增加堆栈。