C 程序的堆栈会缩小吗?堆栈、程序

2023-09-07 03:23:31 作者:贱人终会弃良人怎会离。

我注意到每个正在运行的 C 程序都有一个名为 [stack] 的私有映射,它最初非常小(在我的机器上为 128k),但会增长以容纳任何自动变量(直到堆栈大小限制).我假设这是我的程序的调用堆栈所在的位置.

I've noticed that every running C program has a private mapping called [stack] that is initially quite small (128k on my machine), but will grow to accomodate any automatic variables (up to the stack size limit). I assume this is where the call stack of my program is located.

但是,它似乎永远不会缩小到原来的大小.有什么方法可以在不终止进程的情况下释放内存?

However, it doesn't seem to ever shrink back to its original size. Is there any way to free up that memory without terminating the process?

C 栈是如何在内部实现的;什么会按需增加 [stack] 映射的大小?一些编译器生成的代码、C 库还是操作系统?涨价是从哪里触发的?

How is the C stack implemented internally; what increases the size of the [stack] mapping on demand? Some compiler generated code, the C library or the operating system? Where is the increase triggered?

更新:我在 x86-64 上使用 Linux 3.0.0、gcc 4.6.1 和 glibc6;因为这可能是非常具体的实现,所以任何关于它如何工作的信息都可以.

Update: I'm using Linux 3.0.0, gcc 4.6.1 and glibc6 on x86-64; as this is probably pretty implementation specific, any information on how it works there would be fine.

推荐答案

在 Linux/MMU 中(在 !MMU 中你不能增长堆栈),堆栈是在页面错误处理程序中增长的.对于 x86,是否增加堆栈由 arch/x86/mm/fault.c:do_page_fault() 中的以下代码决定:

In Linux/MMU (in !MMU you cannot grow the stack), the stack is grown in the page fault handler. For x86, whether to grow the stack is decided by the following code from 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 是否允许增加堆栈,是否有过多的过度使用等...,最后增加堆栈.

expand_stack() checks the usual RLIMITS (RLIMIT_AS, RLIMIT_STACK, RLIMIT_MEMLOCK), whether LSMs will allow to grow the stack, whether there's too much overcommit, etc..., and finally grows the stack.