最近、OSが異なる3つのデバイスでスタックの制限をテストしました(制限とは、スタックが持つことができるレベルの最大数を意味します)。2^ 16レベルに達するたびに、オーバーフローエラー、および2 ^ 16-1を配置すると、正しく動作します。
だから私の質問は-それは本当ですか?スタックには、定義により最大値2 ^ 16-1がありますか、それともOSに依存しますか?
最近、OSが異なる3つのデバイスでスタックの制限をテストしました(制限とは、スタックが持つことができるレベルの最大数を意味します)。2^ 16レベルに達するたびに、オーバーフローエラー、および2 ^ 16-1を配置すると、正しく動作します。
だから私の質問は-それは本当ですか?スタックには、定義により最大値2 ^ 16-1がありますか、それともOSに依存しますか?
回答:
これは、オペレーティングシステム固有(およびコンピューター固有)に強く依存しており、一部の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、RAMの唯一の2Kバイトとするので、確かにその多くを再発することはできません。Arduinosで実際に可能なスタックフレームは数百個だけだと思います。
here i mean by limit the maximum number of levels that can the stack have
レベルは?