多少堆栈使用量过多?


22

最近,当我编写C或C ++时,我会在堆栈上声明所有变量,只是因为它是一个选项,与Java不同。

但是,我听说在栈上声明大的东西是个坏主意。

  1. 为什么会这样呢?我认为涉及到堆栈溢出,但是我不清楚原因为何。
  2. 堆栈上有多少东西太多了?

我不是想将100MB的文件放在堆栈上,而只是将十几个千字节数组用作字符串缓冲区或其他任何东西。这是堆栈使用过多吗?

(对不起,如果有重复,搜索堆栈时会不断引用堆栈溢出。甚至没有调用堆栈标记,我只是使用了抽象标记。)


1
您如何“将100MB文件放入堆栈”?缓冲区和容器的实现(以及类似的std :: string)通常使用堆来存储其有效负载。
墨菲

2
在涉及到递归之前,您可以在每个函数/方法上避免大量的堆栈使用,然后冒着严重限制功能(相对于递归深度)的风险,因此在递归函数中,您希望使用尽可能少的局部尽可能多的变量/堆栈空间。
Erik Eidt

3
请注意,C&C ++是不同的。局部std::vector<int>变量不会占用很多堆栈空间,大多数数据在堆中。
Basile Starynkevitch

Answers:


18

这取决于您的操作系统。在Windows上,典型的堆栈最大大小为1MB,而在典型的现代Linux上,堆栈的最大大小为8MB,尽管这些值可以通过各种方式进行调整。如果整个调用堆栈中堆栈变量的总和(包括底层开销,例如返回地址,基于堆栈的参数,返回值占位符和对齐字节)超过了该限制,则会导致堆栈溢出,这通常会降低您的程序,没有任何恢复的机会。

通常几千字节就可以了。数十千字节是危险的,因为它开始累加。数百千字节是一个非常糟糕的主意。


1
是不是典型的堆栈限制兆字节(即通常不止一个,但大概不到十)今天在2016年?在我的Linux桌面上,默认情况下为8Mb ...
Basile Starynkevitch 2016年

“在[...] Linux中,堆栈典型的最大大小为1MB” $ ulimit -a在等我的系统返回stack size (kbytes, -s) 8192
Murphy

9

唯一有效的答案是模糊的:“太多是当堆栈溢出时。”

除非您完全控制程序入口点和所讨论函数之间的每一行代码的实现,否则您都不能假设有多少堆栈可用。例如,您不能保证调用此函数将永远不会导致堆栈溢出:

void break_the_camels_back()
{
    int straw;
    ...
}

在现代Unix上,默认的8 MiB堆栈有很大的发展空间,尤其是对于像我这样的人来说,他像个杰瑟一样记得8位堆栈指针的CPU。实际的现实是,如果不尝试,您不太可能会失败。如果这样做,超出堆栈限制通常被认为是分段违规,并且具有足够内存管理能力以检测到它的系统会SIGSEGV在发生这种情况时发送一个。

您确实有两个选择。首先是不要猜测有多少可用堆栈,然后询问系统。任何符合POSIX的getrlimit(2)功能都会告诉您上限。 RLIMIT_STACK是您想要的特定限制。第二个是监视程序正在使用多少堆栈,并基于此决定自动变量与动态内存分配。据我所知,没有标准函数来确定使用了多少堆栈,但是类似的程序valgrind可以为您分析。


4

如果您在堆栈上分配了10,000个字节的数组,则该数组的大小将受到限制。10,000可能很多,但是如果您需要10,001字节,则程序可能崩溃甚至更糟。因此,在这种情况下,您需要能够适应所需大小的东西,而这些东西不会放在堆栈中。

堆栈上的字符串缓冲区的固定大小数组不是问题,因为它们将内存保留在堆栈上,因为固定大小的缓冲区是等待发生的致命问题,因此它们是一个问题。

但是,如果您使用C ++,并在堆栈上声明例如std :: string或std :: vec,那么堆栈上的内容实际上将是固定的且很小。实际数据将存储在堆中。您可以在std :: string实例中存储一百万个字符,它在堆栈上仅需要非常少量的数据(通常为8至24个字节,具体取决于实现),而在堆上则仅需要一百万个字节。


2

1 MB对于* nix是一个很好的估计。递归可能是堆栈分配与堆栈溢出结合使用的主要原因。但是,在大多数情况下,表面看起来似乎太大而无法放置在堆栈上的上帝对象经过精心设计,可以管理其在堆上的内部内存,并且仅将堆栈用作弹出堆栈时自动销毁的一种方式。析构函数将释放内部管理的大量内存。std容器是按照这种方式设计的,而共享/唯一指针也是按照这种方式设计的。

重要的是不要在像char [1024 * 1024]这样的堆栈上分配大块的原始mem,并设计类来包装堆分配并仅出于自动调用析构函数的便利而使用堆栈。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.