1

そこで、システムの限界を試すために、意図的にスタックオーバーフローを引き起こすおもちゃのCプログラムを作成しました。

#include <stdio.h>

int kefladhen(int i) {
    int j = i + 1;
    printf("j is %d\n",j);
    kefladhen(j);
}

int main() {
    printf("Hello!:D\n");
    kefladhen(0);
}

セグメンテーション違反の前に印刷された最後の行が「jis174651」であることに驚いた。もちろん、実行するたびに正確な数は少し異なりますが、一般的に、4GBのLinuxラップトップのプロセスのメモリを使い果たすのに174,000の奇数スタックフレームで十分であることに驚いています。printfにオーバーヘッドが発生しているのではないかと思いましたが、kefladhen()を再帰的に呼び出す前にprintfが戻るため、スタックポインタは以前の場所に戻るはずです。呼び出しごとに正確に1つのintを格納しているので、各スタックフレームは合計で8バイトだけである必要があります。つまり、174万の奇数は、実際に使用されるメモリの約1メガバイトと半分にすぎません。これは、私にはかなり低いように思われます。私はここで何を誤解していますか?

4

3 に答える 3

8

...しかし、一般的に、4GBのLinuxラップトップのプロセスのメモリを使い果たすのに174,000の奇数スタックフレームで十分であることに驚いています...

スタックは一般的なメモリプールではないことに注意してください。スタックは、スタックを提供する目的で事前に割り当てられたチャンクです。マシン上の4GBのメモリのうち1MBである可能性があります。私の推測では、スタックサイズは約1.3MBです。これは、174,651個の8バイトフレーム(リターンアドレス用に4バイト、int)用に4バイトで十分です。

于 2012-04-30T10:54:56.467 に答える
2

ここでの主な誤解は、スタックがそれ自体で動的に成長しないことだと思います。静的に比較的小さい数に設定されますが、実行時に変更できます(callでどのように行われるかを説明する回答へのリンクがありsetrlimitます)。

于 2012-04-30T10:58:09.027 に答える
1

他の人はすでにスタックのサイズと割り当てについて議論しています。「実行するたびに正確な数が少し変化する」理由は、マルチスレッドシステムのキャッシュパフォーマンスに関係しています。

一般に、スタックに事前に割り当てられたメモリはページアラインされると予想できます。ただし、開始スタックポインターは、スレッド間/プロセス間/タスク間で異なります。これは、キャッシュラインのフラッシュ、無効化、およびロードを回避するのに役立ちます。すべてのタスク/スレッド/プロセスがスタックポインターに対して同じ仮想アドレスを持っている場合、コンテキストスイッチが発生するたびにキャッシュの衝突が増えることが予想されます。この可能性を減らすために、多くのOSは、開始スタックページ内のどこかに開始スタックポインターを持っていますが、必ずしも最上部または同じ位置にあるとは限りません。したがって、コンテキストスイッチが発生し、後続のスタックアクセスが発生すると、...

  1. 変数がすでにキャッシュにある可能性が高くなります
  2. キャッシュの衝突が発生しない可能性が高くなります

お役に立てれば。

于 2012-04-30T13:56:47.767 に答える