スタックの使用量は多すぎますか?


22

最近、CやC ++を書いているときに、Javaの場合とは異なり、それがオプションであるという理由だけで、すべての変数をスタック上で宣言します。

しかし、スタック上で大きなものを宣言するのは悪い考えだと聞いたことがあります。

  1. なぜこれが当てはまるのですか?スタックオーバーフローが関係していると思いますが、なぜ発生するのかはあまりわかりません。
  2. スタック上のものはどれくらい多すぎますか?

スタックに100MBのファイルを配置しようとはしていません。文字列バッファーなどとして使用するために、数十キロバイトの配列を配置しようとしています。これはスタックの使用量が多すぎませんか?

(重複する場合は申し訳ありませんが、スタックの検索はスタックオーバーフローへの参照を提供し続けます。呼び出しスタックタグさえありません。抽象タグを使用しました。)


1
「スタックに100MBファイルを置く」方法は?バッファおよびコンテナの実装(およびstd :: stringのようなもの)は通常、ヒープを使用してペイロードを格納します。
マーフィー

2
再帰が関与するまで、関数/メソッドごとにかなりの量のスタックを使用して逃げることができ、再帰の深さに対して機能を大幅に制限するリスクがあるため、再帰関数内では、ローカルとして使用したくない可能な限り変数/スタックスペース。
エリックエイド

3
CとC ++は異なることに注意してください。ローカルstd::vector<int>変数は多くのスタックスペースを消費せず、ほとんどのデータはヒープ内にあります。
バジルスタリンケビッチ

回答:


18

オペレーティングシステムによって異なります。Windowsでは、スタックの一般的な最大サイズは1MBですが、典​​型的な現代のLinuxでは8MBですが、これらの値はさまざまな方法で調整できます。コールスタック全体のスタック変数(リターンアドレス、スタックベースの引数、戻り値のプレースホルダー、アライメントバイトなどの低レベルのオーバーヘッドを含む)の合計がその制限を超えると、スタックオーバーフローが発生します。回復のチャンスのないプログラム。

通常、数キロバイトで十分です。合計すると数十キロバイトが危険です。数百キロバイトは非常に悪い考えです。


1
2016年の今日の典型的なスタック制限は、メガバイト(つまり、通常は1メガバイト以上、おそらく1ダース未満)に制限されていませんか?私のLinuxデスクトップでは、それは...デフォルトでは8Mバイトです
バジーレStarynkevitch

「[...] Linuxでは、システムの典型的なスタックの最大サイズは1MBです」$ ulimit -aなどが返されますstack size (kbytes, -s) 8192
マーフィー

9

唯一の有効な答えはあいまいです:「スタックがオーバーフローするときが多すぎます」。

プログラムのエントリポイントと問題の関数の間のすべてのコード行の実装を完全に制御していない限り、利用可能なスタックの量について仮定することはできません。たとえば、この関数を呼び出してもスタックオーバーフローが発生しないことを保証することはできません。

void break_the_camels_back()
{
    int straw;
    ...
}

最近のUnixのデフォルトの8 MiBスタックは、スタックが進むにつれて、特に8ビットスタックポインターを持つCPUを覚えるのに十分なギーザーを持っている私のような人にとっては、かなりのスペースがあります。現実的な現実は、あなたが試みずにそれを吹き飛ばす可能性は低いということです。その場合、通常、スタック制限を超えることはセグメンテーション違反とみなされ、それを検出するのに十分なメモリ管理を備えたシステムは、SIGSEGV発生時に送信します。

いくつかのオプションがあります。まず、使用可能なスタックの量を推測せずにシステムに問い合わせます。POSIXに準拠するものには、getrlimit(2)上限を知らせる機能があります。 RLIMIT_STACK必要な特定の制限です。2つ目は、プログラムが使用しているスタックの量を監視し、それに基づいて自動変数と動的メモリ割り当てを決定することです。私が知る限り、スタックの使用量を決定する標準関数はありませんが、同様のプログラムvalgrindがあなたのためにそれを分析できます。


4

スタックに10,000バイトの配列を割り当てると、その配列のサイズは制限されます。10,000は大量かもしれませんが、10,001バイトが必要な場合は、プログラムがクラッシュしたり悪化したりする可能性があります。したがって、この状況では、必要なサイズに適合するものが必要であり、そのようなものはスタック上にありません。

スタック上の文字列バッファの固定サイズの配列は、メモリをスタック上に保持するため問題ありません。固定サイズのバッファは発生を待つ致命的な問題であるため、問題です。

ただし、C ++を使用し、スタックでstd :: stringまたはstd :: vecなどを宣言した場合、スタック上にあるものは実際には固定サイズと小さなサイズになります。実際のデータはヒープに保存されます。std :: stringインスタンスには100万文字を格納でき、スタックには非常に少量のデータ(実装に応じて通常8〜24バイト)が、ヒープには100万バイトしかかかりません。


2

* nixの適切な推定値は1 MBです。再帰は、スタックの割り当てと組み合わせたスタックオーバーフローの主な理由です。ただし、ほとんどの場合、表面上はスタックに配置するには大きすぎると思われるゴッドオブジェクトは、ヒープ上の内部メモリを管理し、スタックがポップされたときに自動的に破棄する方法としてのみスタックを使用するように設計されています デストラクタは、内部で管理されているメモリの巨大なチャンクを解放します。stdコンテナはそのように設計されており、共有/一意のポインタも同様に設計されています。

重要なことは、char [1024 * 1024]のようなスタック上に生memの大きなチャンクを割り当てず、ヒープ割り当てをラップし、デストラクタを自動的に呼び出すためだけにスタックを使用するクラスを設計することです。

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