プログラムのC / C ++最大スタックサイズ


115

100 X 100アレイでDFSを実行したい。(たとえば、配列の要素はグラフのノードを表します)したがって、最悪の場合を想定すると、再帰関数呼び出しの深さは最大10000になり、各呼び出しは最大で20バイトを使用します。それで、スタックオーバーフローの可能性があるのは実行可能な手段ですか?

C / C ++のスタックの最大サイズはいくつですか?

両方のgccを指定してください
1)Windows上のcygwin
2)Unix

一般的な制限は何ですか?


11
再帰せずに深さ優先検索を実装できることをご存知ですか?
セバスチャン

4
いいえ、わかりません。説明してください。
avd 2009

1
私は自分の回答で再帰なしのDFSの小さな例を作成しました
Andreas Brinck 09

56
さらに、実際のスタックオーバーフローに関する質問に1つ
Sam Watkins、

3
@SamWatkinsええ、名前スタックオーバーフローを持つ私にとって最大の問題の一つは、私はGoogleで「スタックオーバーフロー」を検索し、このウェブサイトで終わるが、必ずしもそうではない/少ないスタックオーバーフロー...についての質問であるかもしれません
lalilulelost

回答:


106

Visual Studioでは、デフォルトのスタックサイズは1 MBだと思うので、再帰の深さが10,000の場合、各スタックフレームは最大で〜100バイトで、DFSアルゴリズムには十分です。

Visual Studioを含むほとんどのコンパイラでは、スタックサイズを指定できます。一部の(すべての)Linuxフレーバーでは、スタックサイズは実行可能ファイルの一部ではなく、OSの環境変数です。次に、スタックサイズを確認ulimit -sして、たとえば次のように新しい値に設定できます。ulimit -s 16384

ここにリンクがあります、gccのデフォルトスタックサイズのです。

再帰なしのDFS:

std::stack<Node> dfs;
dfs.push(start);
do {
    Node top = dfs.top();
    if (top is what we are looking for) {
       break;
    }
    dfs.pop();
    for (outgoing nodes from top) {
        dfs.push(outgoing node);
    }
} while (!dfs.empty())

12
参考までに、スタックの代わりにFIFOを使用することを除いて、BFSは同じです。
スティーブジェソップ

はい、またはSTL-lingoではpop_front / push_backでstd :: dequeを使用します
Andreas Brinck

DFSとスタックの結果は、再帰バージョンとは異なります。いくつかのケースではそれは問題ではありませんが、他の場合(例:トポロジーソート)、間違った結果が得られます
spin_eight

はい、VSのデフォルトの制限は確かに1MBです。詳細と別の値を設定する方法については、Microsoftのドキュメントを
ご覧

そのようなアルゴリズムには、再帰ではなく明示的なスタックデータ構造を使用したいので、1。システムスタックのサイズに依存せず、2。アルゴリズムを変更して、スローせずにキューや優先キューなどの異なるデータ構造を使用できます。すべてのコードを出力します。
Sam Watkins、

47

多くの場合、スレッドのスタックは小さくなります。リンク時にデフォルトを変更することも、実行時に変更することもできます。参考までに、いくつかのデフォルトは次のとおりです。

  • glibc i386、x86_64 7.4 MB
  • Tru64 5.1 5.2 MB
  • Cygwin 1.8 MB
  • Solaris 7..10 1 MB
  • MacOS X 10.5 460 KB
  • AIX 5 98 KB
  • OpenBSD 4.0 64 KB
  • HP-UX 11 16 KB


17

プラットフォーム依存、ツールチェーン依存、ulimit依存、パラメーター依存....これはまったく指定されておらず、それに影響を与える可能性のある多くの静的および動的プロパティがあります。


4
「一般的な制限」はありません。Windowsでは、デフォルトのVC ++リンカーオプションとデフォルトのCreateThread動作で、通常はスレッドあたり約1 MiBです。Linuxでは、無制限のユーザーがいるので、通常は制限がないと思います(スタックは、アドレス空間のほぼ全体を占めるように下向きに成長する可能性があります)。基本的に、質問する必要がある場合は、スタックを使用しないでください。
DrPizza 2009

1
組み込みシステムでは、4k以下になる可能性があります。その場合は、スタックを使用することが合理的である場合でも確認する必要があります。答えは通常、ガリアの肩をすくめることです。
スティーブジェソップ

1
ええ、そうです、カーネルモードの場合もそうです。
DrPizza 09

6

はい、スタックオーバーフローの可能性があります。CおよびC ++標準では、スタックの深さなどは規定されていません。これらは一般に環境問題です。

最も適切な開発環境やオペレーティングシステムでは、リンク時またはロード時に、プロセスのスタックサイズを調整できます。

より的を絞った支援のために、使用しているOSと開発環境を指定する必要があります。

たとえば、Ubuntu Karmic Koalaでは、gccのデフォルトは2Mが予約され、4Kがコミットされますが、プログラムをリンクするときに変更できます。それを行うには、--stackオプションを使用しますld


2
@lex:一般的な制限はありません。それは多くのパラメーターに依存します。
Michael Foukarakis、2009

@paxdiablo:WHatは予約およびコミットの意味ですか?
2009

2
予約済みは割り当てられるアドレススペースの量であり、コミット済みはバッキングストレージを接続する量です。つまり、アドレス空間を予約しても、必要なときにメモリがそこにあるわけではありません。4Kを超えるスタックを使用しない場合は、他の1.6Mの実際のメモリを浪費していません。十分なスタックがあることを保証したい場合は、予約済みとコミット済みは同一でなければなりません。
paxdiablo 2009

2
@paxdiablo 2M-4kは160万ではありません。ただ言って。(私はあなたのコメントを読んだ最初の3回を混乱させた)
グリフィン

2
@ griffin、3人以上で最初にそれをキャッチした人への称賛。もちろん、私は「残りの部分」を意味しました。別の考えられる間違いをしないように、実際の数字は避けます:-)
paxdiablo

5

私は仕事でスタックを使い果たしました、それはデータベースであり、いくつかのスレッドを実行していました。基本的に、前の開発者がスタックに大きな配列をスローし、スタックはとにかく低かったです。ソフトウェアは、Microsoft Visual Studio 2015を使用してコンパイルされました。

スレッドはスタックを使い果たしましたが、黙って失敗して続行しましたが、スタック上のデータの内容にアクセスするようになったときにのみ、スタックがオーバーフローしました。

私ができる最善のアドバイスは、スタックで配列を宣言しないことです。特に複雑なアプリケーションやスレッドでは、代わりにヒープを使用してください。それがそこにあります;)

また、スタックの宣言時にすぐに失敗するのではなく、アクセス時にのみ失敗する可能性があることにも注意してください。私の推測では、コンパイラーはウィンドウの下でスタックを「楽観的に」宣言します。つまり、スタックが宣言されていて、それを使用するようになるまで十分なサイズであると想定して、そこにスタックがないことがわかります。

オペレーティングシステムが異なれば、スタック宣言ポリシーも異なります。これらのポリシーについてご存知の場合は、コメントを残してください。


3

長方形配列で深さ優先検索を実行することで何を意味するのかはわかりませんが、あなたが何をしているのか知っていると思います。

スタック制限が問題である場合、再帰的ソリューションを、ヒープから割り当てられたスタックに中間値をプッシュする反復的ソリューションに変換できるはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.