web-dev-qa-db-ja.com

プログラムスタックとヒープ、それらはどのように機能しますか?

実行中のすべてのプロセスの仮想メモリにページが関連付けられており、必要に応じてメインメモリに読み込まれるページはほとんどないことを私は知っています。また、プログラムには動的メモリを割り当てるためのスタックとヒープがあることも知っています。これが私の質問です。

  1. スタックもメインメモリの一部のページの一部ですか?
  2. プログラムが待機状態に移行するとどうなりますか?スタックポインタ、プログラムカウンタ、その他の情報はどこに保存されますか?
  3. スタックが成長し、ヒープが成長するのはなぜですか?
  4. L1、L2キャッシュには、連続したメモリのチャンクを1つだけ含めることができますか、それともスタックとヒープの一部を含めることができますか?

これらのことをカバーする良い本をお勧めできますか?

27
Boolean
  1. はい-スタックは通常、メモリの「下位」アドレスに格納され、上限に向かって上向きにいっぱいになります。ヒープは通常、アドレススペースの「最上位」に格納され、スタックに向かって大きくなります。

  2. O/Sは、実行中のプロセスごとに「コンテキスト」を格納します。プロセス状態を保存および復元する操作は、「コンテキストスイッチ」と呼ばれます。

  3. ただの慣習AFAIK。スタックは実際には「成長」しませんが、割り当ては固定されています。

  4. キャッシュには、(最近または近くで)使用されたRAMの部分のスナップショットが含まれているだけです。いつでも、キャッシュ内のアドレス空間の任意の部分のメモリを保持できます。表示される内容ここで、キャッシュの構造パラメーター(ブロック長、結合性、合計サイズなど)に大きく依存します。

基礎となるハードウェアおよびハードウェアの「管理」方法に関するオペレーティングシステムに関する本の良い参考資料として、 コンピュータアーキテクチャ:定量的アプローチ をお勧めします。

14
vicatcu

これはそれらの質問の私の理解です:

  1. スタックもメインメモリの一部のページの一部ですか?

    はい、スタックは通常、プロセスのアドレス空間にも格納されます。

  2. プログラムが待機状態に移行するとどうなりますか?スタックポインタ、プログラムカウンタ、その他の情報はどこに保存されますか?

    オペレーティングシステムがプロセスをアクティブから待機に移行すると、すべてのレジスタ(スタックポインタとプログラムカウンタを含む)がカーネルのプロセステーブルに格納されます。次に、再びアクティブになると、OSはそのすべての情報を元の場所にコピーします。

  3. スタックが大きくなり、ヒープが大きくなるのはなぜですか?

    これは、通常、同じアドレススペースを共有する必要があるためです。便宜上、それぞれがアドレススペースの一方の端から始まります。それから彼らはお互いに向かって成長し、その成長を成長させる行動を与えます。

  4. L1、L2キャッシュには、連続したメモリのチャンクを1つだけ含めることができますか、それともスタックとヒープの一部を含めることができますか?

    CPUキャッシュは、最近使用されたメモリのチャンクを格納します。スタックとヒープの両方がメインメモリに格納されるため、キャッシュには両方の部分を含めることができます。

。スタックが小さくなり、ヒープが大きくなるのはなぜですか?

一部のシステム(たとえば、一部のHPシステム)では、スタックがダウンではなくアップアップすることに注意してください。また、他のシステム(IBM/390など)には、noの実際のハードウェアスタックはまったくありませんが、ユーザーから動的に割り当てられるページのプールがあります。スペースメモリ。

ヒープには一般に、any方向に成長する可能性があります。これは、ヒープに多くの割り当ておよび割り当て解除の穴が含まれている可能性があるためです。 LIFOスタックタイプの構造としてよりもページの緩いコレクション。そうは言っても、ほとんどのヒープ実装は、所定のアドレス範囲内でスペース使用量を拡大し、必要に応じて拡大および縮小します。

3
David R Tribble

プロテクトモードのオペレーティングシステム(WindowsやLinuxなど)を使用する場合、各プロセスには、特定のプロセスで使用できるメモリページがたくさんあります。より多くのメモリが必要な場合は、より多くのメモリをページングできます。

通常、プロセスは与えられたメモリを2つの部分に分割します。 1つはヒープで、もう1つはスタックです。スタックの最下部は、armのスタックポインタr13およびx86のespによって指定されます。スタック上に変数を作成すると、スタックポインターが移動して、必要な追加スペースを確保します。これは、アセンブラ命令Pushによって実行されます。同様に、変数がスコープ外の場合、スタックからPOPされます。

通常、プッシュによりスタックポインタがデクリメントされ、スタックポインタの値より上の値が「スタック上」に残ります。

メモリの他の部分は、ヒープに使用できます。これは、mallocまたはnewを使用して割り当てることができます。各スレッドには独自のスタックが必要ですが、プロセス内の他のスレッドとヒープを共有する場合があります。

カーネルがスレッドを再スケジュールすると、スタックレジスタが格納され、スタックレジスタが新しいスタックに変更されます。スケジューリングの方法に応じて、プログラムカウンタを格納する必要がある場合とない場合があります。

キャッシュは、スタックまたはヒープとは何の関係もありません。これはプロセッサによって管理され、CPUが必要とするデータを手元に置いて、バスがデータをフェッチするのを待つ必要がないようにする方法を提供します。メインメモリにあるものがキャッシュに保存されているものと同じであることを確認するのは完全にCPU次第です。キャッシュについて本当に心配する必要があるのは、DMAを使用するときだけです。 CPUがキャッシュを信頼せず、実際にメインメモリからデータをフェッチするように、キャッシュを手動でフラッシュまたは同期する必要があります。

1
doron

私の教授の スライド を私のアーキテクチャクラスからチェックしてください。ユニット6。あなたが尋ねたすべてのことと他の人が答えたすべて、そしてもっと深い知識が必要な場合はもっと理解するのに本当に役立ちました。

1
madCode