堆栈什么时候真的溢出?

Mur*_*ali 4 stack

无限递归是唯一的情况还是因其他原因而发生?堆栈大小是否与堆一样增长?

对不起,如果之前已经提出过这个问题,如果是这种情况,我们将非常感谢他们的链接.

Rus*_*ist 10

我不能代表所有平台,但事实上,我只是花了一些时间使用Windows .exe文件(我的意思是,实际上研究它们的二进制格式 - 我知道在某种意义上我们所有人在这里工作可执行文件;)).我敢打赌大多数其他平台都有类似的功能,但我并不是很熟悉它们.

部分文件格式本身包含两个与当前讨论相关的值:

typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    ...
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
Run Code Online (Sandbox Code Playgroud)

来自MSDN:

SizeOfStackReserve

要为堆栈保留的字节数.只有SizeOfStackCommit成员指定的内存在加载时提交; 其余部分一次可用一页,直到达到此保留金额.

SizeOfStackCommit

要为堆栈提交的字节数.

换句话说,链接器指定程序堆栈的最大大小.如果达到最大尺寸,则会溢出 - 无论您如何达到最大尺寸.你可以编写一个简单的程序,只需分配一个比最大堆栈大小更大的单个堆栈变量(比如一个数组),就可以在一行代码中完成.或者你可以通过无限(或有限但非常深)的递归来实现,或者只是通过分配太多的堆栈变量来实现.

默认情况下,Microsoft链接器在X86平台上将此值设置为1MB(在Itanium系统上为4MB).对于现代系统来说,这看起来很小.但是,更现代的Windows版本对这些值的解释略有不同.它不是完全限制堆栈,而是限制堆栈将使用的物理内存.如果您的堆栈超出此范围,虚拟内存将会涉及,所以您应该仍然很好......假设您有足够的虚拟内存.

请记住,即使在具有大量RAM和磁盘上大量虚拟内存的现代系统上,内存可能耗尽.您只需要分配大量数据.

所以,长话短说:是否有可能在没有无限递归的情况下溢出堆栈?当然.可能吗?不是真的,除非你分配真正巨大的物体.


Dan*_*den 5

当堆栈指针被推出操作系统为堆栈分配的内存块时,堆栈溢出.一些操作系统会随着它的增长而调整堆栈大小(IIRC Linux会这样做),而在其他操作系统中,堆栈大小在进程或线程的开始时是固定的(IIRC Windows会这样做).

堆栈溢出的可能原因:

  • 无限数量的堆栈帧(例如来自无界递归)
  • 试图从堆栈中分配大块
  • 堆栈上分配的缓冲区的缓冲区溢出

可能还有其他原因,我无法想到我的头脑.