最近,我在三个具有不同操作系统的设备上测试了堆栈的限制(按限制,我的意思是堆栈可以具有的最大级别数),并且我注意到,每次达到2 ^ 16级别时,它都会给我溢出错误,当我放2 ^ 16-1时,它可以正常工作。
所以我的问题是-是这样吗?根据定义,堆栈是否具有最大限制2 ^ 16-1还是取决于操作系统?
最近,我在三个具有不同操作系统的设备上测试了堆栈的限制(按限制,我的意思是堆栈可以具有的最大级别数),并且我注意到,每次达到2 ^ 16级别时,它都会给我溢出错误,当我放2 ^ 16-1时,它可以正常工作。
所以我的问题是-是这样吗?根据定义,堆栈是否具有最大限制2 ^ 16-1还是取决于操作系统?
Answers:
它是特定于操作系统的(和特定于计算机的),并且在某些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 recur
)recur 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上最多只有几百个堆栈框架。
here i mean by limit the maximum number of levels that can the stack have
什么水平?