堆栈限制


10

最近,我在三个具有不同操作系统的设备上测试了堆栈的限制(按限制,我的意思是堆栈可以具有的最大级别数),并且我注意到,每次达到2 ^ 16级别时,它都会给我溢出错误,当我放2 ^ 16-1时,它可以正常工作。

所以我的问题是-是这样吗?根据定义,堆栈是否具有最大限制2 ^ 16-1还是取决于操作系统?


5
here i mean by limit the maximum number of levels that can the stack have什么水平?
tkausl


3
您如何测试?您是否使用2字节(双字)作为输入?
pro3carp3

6
您使用哪种编程语言?这样一个固定数目的尖锐限制表明,这是特定于语言的运行时的故意限制,而不是操作系统分配的堆栈大小的故意限制。例如,默认情况下python似乎强制执行限制1000,以防止您遇到实际的堆栈溢出(很难从真实的堆栈溢出中恢复)
CodesInChaos

Answers:


20

它是特定于操作系统的(和特定于计算机的),并且在某些OS上,您可以使用一些方法来配置(甚至增加)限制。它甚至是特定于编译器的(或特定于您的编程语言实现的),因为某些编译器(包括用于某些有限种类的C代码的最新GCC)能够优化某些尾调用

(某些编程语言规范要求尾调用优化,例如R5RS

我不确定您的问题是否有意义(当然也不是您的2 16限制)。在我的Linux桌面(Debian / Sid / x86-64,Linux 4.9内核,32Gb RAM,Intel i5-4690S)上,我的调用堆栈可能高达8兆字节(如果我真的想这样做,可以增加该限制) )。

多线程ASLR使您的问题变得更加复杂。参见例如pthread_attr_setstack(3)。另请阅读有关拆分堆栈(通常由Go实现使用)和有关延续传递样式的信息。另请参阅答案。

对于它的价值,我只是尝试了以下C99(以及C11)代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void recfun(int x, int d) {
  printf("start recfun x=%d d=%d\n", x, d);
  fflush(NULL);
  if (d>0)
    recfun(x+1, d-1);
  printf("end recfun x=%d d=%d\n", x, d);
}

int main(int argc, char**argv) {
  int md = argc>1?atoi(argv[1]):10000;
  printf ("start md=%d\n", md);
  recfun(0, md);
  printf("end md=%d clock=%ld µs\n", md, clock());
}    
// eof recur.c

并且我能够运行该recur程序(与GCC 6一起编译gcc -Wall -O recur.c -o recurrecur 161000 (远高于2 16的限制)。有了recur 256000它也起作用。有了recur 456000它崩溃(与堆栈溢出的水平x=272057)。我没有其他测试的耐心。在您的计算机上尝试一下。不要忘记要求优化。

经验法则(对于台式机,笔记本电脑,平板电脑)可能是将通话堆栈保持在1兆字节以下。

通过传递-fstack-usage gcc我,我得到以下recur.su文件(数字以字节为单位,与我的8Mb堆栈限制直觉一致;请不要忘记main在执行execve(2时由内核安装的调用框架,更重要的是初始堆栈布局) ...,对于crt0):

 recur.c:5:10:recfun    32  static
 recur.c:13:9:main  16  static

PS。我的Arduino的Atmega328仅具有2KB的RAM,因此当然不能重复那么多。我猜想在Arduino上最多只有几百个堆栈框架。


3

Windows进程主线程的堆栈大小由链接器设置。默认值为1MB,但可以使用/ STACK开关进行调整。以后创建的线程可以使用CreateThread函数的dwStackSize参数。

所以..如果您要测试各种Windows操作系统,则它们的默认堆栈大小至少在NT4.0之前都相同。

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.