7

グローバル変数がプログラムのどこに格納されているかを正確に理解したいです。スタック上?ヒープ上?何処か別の場所?

そのために、この小さなコードを書きました。

int global_vector[1000000];
int main () {
    global_vector[0] = 1; // just to avoid a compilation warning
    while(true); // to give me time to check the amount of RAM used by my program
    return 0;
}

をどれだけ大きくしてもglobal_vector、プログラムはほんのわずかな量の RAM しか使用しません。この理由がわかりません。誰か説明してくれませんか?

4

3 に答える 3

11

これは完全に実装に依存しますが、通常、グローバル変数はスタックとヒープとは別の特別なメモリ セグメントに格納されます。このメモリは、実行可能ファイル自体の内部の固定サイズのバッファとして、またはオペレーティング システムによって起動時にプログラムに与えられるセグメントに割り当てることができます。

メモリ使用量が増えていない理由は、おそらく OS による仮想メモリの処理方法に関係しています。最適化として、オペレーティング システムは、実際に使用しない限り、その巨大な配列のプログラムに実際にメモリを与えません。配列の内容全体を for ループするようにプログラムを変更してみて、それによって RAM の使用量が増加するかどうかを確認してください。(コンパイラのオプティマイザが巨大な配列を削除している可能性もあります。これは、ほとんど完全に使用されていないためです。すべての値を読み書きするループを配置すると、コンパイラがそれを保持するように強制される場合もあります)。

お役に立てれば!

于 2012-08-27T20:18:59.967 に答える
5

使用しないため、オプティマイザーはおそらく配列を完全に削除しています。

于 2012-08-27T20:18:31.307 に答える
4

この場合のように、明示的な初期化子が指定されていないグローバル変数は、デフォルトで 0 に初期化されます。それらは.bss セグメントと呼ばれるメモリ領域に配置され、データの初期値を示すオブジェクト ファイル/実行可能ファイルに追加のデータは保存されません (初期値をどこかに保存する必要がある明示的に初期化されたデータとは異なります)。 .

OS がプログラムをロードすると、すべてのセグメントの記述が読み込まれ、そのためにメモリが割り当てられます。.bss セグメントがすべて 0 に初期化されることを認識しているため、実際に大量のメモリを割り当ててからすべて 0 に初期化する必要を回避するための巧妙なトリックを実行できます。プロセスのページ テーブル内のセグメントにアドレス空間を割り当てます。しかし、すべてのページが 0 で埋められた同じページを指しています。

その単一のゼロページも読み取り専用に設定されています。次に、プロセスが .bss セグメント内のデータに書き込むと、ページ フォールトが発生します。OS はページ フォールトをインターセプトし、何が起こっているかを把握してから、そのデータ ページに固有のメモリを実際に割り当てます。その後、命令を再開し、あたかもメモリが最初から割り当てられていたかのように、コードは順調に進みます。

したがって、ゼロで初期化されたグローバル変数または配列がある場合、最終的には、書き込まれることのない各ページ サイズのデータ​​ チャンク (通常は 4 KB) に実際にメモリが割り当てられることはありません。

注: ここでは、「割り当てられた」という言葉を少し曖昧にしています。こういうことを掘り下げると、「予約」や「コミット」などの言葉が出てきそうです。Windows のコンテキストでのこれらの用語の詳細については、この質問このページを参照してください。

于 2012-08-27T20:34:28.360 に答える