为什么这个堆栈溢出得这么快?

时间:2012-04-30 10:51:20

标签: c memory

所以我写了一个玩具C程序,故意造成堆栈溢出,只是为了解决我的系统限制:

#include <stdio.h>

int kefladhen(int i) {
    int j = i + 1;
    printf("j is %d\n",j);
    kefladhen(j);
}

int main() {
    printf("Hello!:D\n");
    kefladhen(0);
}

我很惊讶地发现在分段错误之前打印的最后一行是“j是174651”。当然,每次运行它时,它的确切数量会有所变化,但总的来说,令我惊讶的是,在我的4GB linux笔记本电脑上,有七万多个堆叠帧足以耗尽内存。我认为也许printf会产生一些开销,但printf在我以递归方式调用kefladhen()之前返回,所以堆栈指针应该回到之前的位置。我每次调用只存储一个int,所以每个堆栈帧总共应该只有8个字节,对吧?所以它们中有174,000多个只有大约一兆字节和一半的实际内存,这对我来说似乎很低。我在这里误解了什么?

3 个答案:

答案 0 :(得分:8)

  

...但总的来说,令我惊讶的是,在我的4GB linux笔记本电脑上,有七万多个堆栈帧足以耗尽内存... ...

请注意,堆栈不是常规内存池。堆栈是为了提供堆栈而预先分配的块。机器上的4GB内存可能只有1MB。我的猜测是你的堆栈大小约为1.3MB;对于174,651个8字节帧(返回地址为4个字节,int为4个字节)就足够了。

答案 1 :(得分:2)

我认为这里的关键误解是堆栈本身不会动态增长。它静态设置为相对较小的数字,但您可以在运行时更改它(这里是link to an answer explaining how it is done with setrlimit call)。

答案 2 :(得分:1)

其他人已经讨论过堆栈的大小和分配。之所以“每次运行它时变化的确切数量”都与多线程系统的缓存性能有关。

通常,您可以预期为堆栈预分配的内存是页面对齐的。但是,起始堆栈指针将根据线程到线程/进程到进程/任务到任务而变化。这有助于避免缓存行刷新,失效和加载。如果所有任务/线程/进程具有相同的堆栈指针虚拟地址,则无论何时发生上下文切换,都会发生更多缓存冲突。为了减少这种可能性,许多操作系统将在起始堆栈页面内的某处具有起始堆栈指针,但不一定位于最顶层或相同位置。因此,当发生上下文切换并且发生后续堆栈访问时,存在......

  1. 变量已经更好地存在于缓存中
  2. 更好的机会,不会有缓存冲突
  3. 希望这有帮助。