2

次のCプログラムをMicrosoftVisualStudioExpress2012でコンパイルしています。

int main() {
   int a[300000];
   return 0;
}

これは、msvcr110d.dll!__ crtFlsGetValue()のスタックオーバーフローでクラッシュします。

配列サイズを300,000から200,000に変更すると、正常に機能します(この単純なプログラムは、何も実行しないため、「機能する」と言えます)。

私はWindows7で実行しており、Cygwinでgccを使用してこれを試しましたが、同じ動作が発生します(この場合はセグメンテーション違反)。

一体何?

4

4 に答える 4

5

Cの自動オブジェクトが使用するスペースのサイズ(「スタックサイズ」)には、プラットフォーム固有の制限があります。そのサイズよりも大きいオブジェクト(組み込みプラットフォームでは数キロバイト、デスクトップマシンでは数メガバイト)は、自動オブジェクトとして宣言できません。代わりに、静的または動的にします。

同様に、関数呼び出しの深さ、特に再帰には制限があります。

実際のサイズとその変更方法の詳細については、コンパイラやプラットフォームのドキュメントを確認してください。(たとえば、Linuxのチェックアウトulimit。)

于 2013-01-08T22:37:49.267 に答える
3

スタックに割り当てられており、スタックのサイズが制限されているため、明らかに300000intを保持するのに十分な大きさではありません。

ヒープ割り当てを使用しますmalloc

int* a = malloc(sizeof(int) * 300000);
// ...
free(a);

ヒープはスタックよりもはるかに多くを保持できます。

于 2013-01-08T22:38:10.670 に答える
2

スレッドスタックのサイズは、各プロセスで使用できる仮想アドレススペースの量に有限の制限があるため、従来、オペレーティングシステムによって制限されていました。

スレッドスタックに割り当てられた仮想アドレス空間は、一度割り当てられると変更できないため、ほとんどのスレッドがほとんど使用しない場合でも、かなり大きいが制限されたチャンクを各スレッドに割り当てる以外の戦略はありません。 。

同様に、プロセスが生成できるスレッドの数にも有限の制限があります。

推測では、ここでの制限は1MBであり、Windowsはスレッド数を-たとえば-256に制限します。これは、32ビットプロセスで使用可能な3GB仮想アドレス空間の256MBがスレッドスタックに割り当てられることを意味します-または別のちなみに、1/12。

64ビットシステムでは、明らかに多くの仮想空間を操作できますが、無限再帰をすばやく検出して終了するには、制限を設けることが賢明です。

于 2013-01-08T23:10:07.400 に答える
1

ローカル変数はスタックからスペースを要求します。したがって、十分な大きさの何かを割り当てると、スタックは必然的にオーバーフローします。

于 2013-01-08T22:38:40.867 に答える