C ++には、スタック、ヒープ、および静的に割り当てられた機能の領域という2つではなく、3つのメモリ領域があることを理解しています。2つの質問があります
ヒープがスタックよりもはるかに遅いのはなぜですか?確かに、それは間接参照の1つの余分なレベルである必要がありますか?
静的な「機能」(変数、関数、クラス)に割り当てられたメモリの領域は、ヒープよりも高速なパフォーマンスを提供しますか?
最初にいくつかのサイドノート。正しい用語は、スタックではなく自動であり、ヒープではなく動的です。もう1つは、C ++ 11では、3種類ではなく4種類のメモリが使用できるようになったことです。C ++ 11は、スレッドローカルメモリをミックスに追加します。
自動メモリは、ほとんどのマシンでコールスタックを使用して実装されるため、高速です。必要なのは、スタックポインタを適切な量と出来上がりで調整することだけです。メモリが割り当てられます。動的メモリには、内部でさらに多くの作業が必要です。必要なメモリがプロセスに接続されていない可能性があり、それを実現するにはOSを経由する必要があります。メモリが使用可能な場合でも、動的メモリ管理ツールはメモリを検出して使用中としてマークする必要があります。
静的メモリは、コンパイルおよびリンクプロセスの一部として「割り当て」られます。ソースファイルで静的変数を定義すると、コンパイルされたコードには、リンカーがその変数用のスペースを予約するための特別な命令が含まれます。コンパイラは、C /C++コードをマシンコードに変換します。リンカは、これらのさまざまなデータとコードのチャンクをすべて組み合わせ、アドレスを解決して実行可能なバイナリイメージを形成します。プログラムを実行すると、そのバイナリイメージが(仮想)メモリにロードされます。その静的変数のメモリは、プログラムの実行が開始されるとすぐに存在します。
パフォーマンスに関しては、事前にパフォーマンスについてあまり心配しないことが最善です。静的メモリは高速ですが、多くの欠点があります。最後にやりたいことは、すべてのデータを静的にすることです。
1)ヒープがスタックよりもはるかに遅いのはなぜですか?確かに、それは間接参照の1つの余分なレベルである必要がありますか?
スタックにメモリを割り当てるということは、スタックポインタspを1増やすことを意味するため、ここで、はバイト数です。そのようにspを変更するのは十分に速いです。ヒープを使用すると、多くのことを実行できます。たとえば、空きスロットを見つけたり、メモリ用のOSを要求したりするのは、コストのかかる操作です。N
N
1.スタックがどちらの方向に成長するかに応じて、または減少します。
2)静的な「機能」(変数、関数、クラス)に割り当てられたメモリの領域は、ヒープよりも高速なパフォーマンスを提供しますか?
変数を意味するstatic
場合は、そうです。静的に割り当てられ、プログラムの最後まで存在するため、ヒープよりも高速です。ただし、クラスのようなものはなくstatic
、関数に割り当てられたメモリをこのコンテキストで比較することはできません(質問は私には完全に意味がありません)。
スタック、ヒープ、または静的割り当て領域の速度を比較する場合、比較する速度は2つあります。
まず、アクセスの速度があります。これは3つの領域のそれぞれで同等ですが、ローカル(スタック割り当て)変数は、コンパイラーがCPUレジスターにキャッシュしやすいため、わずかなエッジを持つ可能性があります。それ以外の場合は、基本的にメモリアクセスです。
第二に、割り当ての速度があります。ここで大きな違いが生じます。
静的に割り当てられたオブジェクトは、プログラムの起動時(または動的にロードされたライブラリにある場合はライブラリのロード時間)にメモリを予約するため、プログラムに関する限り、割り当て時間は計り知れないほど短くなります。
スタックに割り当てられたオブジェクトは、コンパイラーが簡単に考慮できる予測可能な割り当てパターン(最後に割り当てられた==最初に割り当て解除されたもの)を採用するため、割り当ても安価です。たとえば、アプリケーションに複数のスレッドがある場合、複数のスタック(各スタックは1つのスレッド用に予約されています)もあるため、スタックメモリへのアクセスについてスレッドが互いに競合する必要はありません。
割り当てられたヒープオブジェクトは難しいものです。ヒープは、以前のグループにうまく収まらないすべてのものに使用されるためです。また、通常、アプリケーション全体でヒープが1つしかないため、ヒープからメモリを割り当てるにはスレッドの同期が必要です。また、割り当て/割り当て解除のパターンはかなりランダムであるため、ヒープの断片化によってヒープメモリが「失われる」ことが多すぎないように対策を講じる必要があります。これはすべて、割り当てまたは割り当て解除を行うときに支払われる時間がかかります。
「ヒープが遅い」という記述は広すぎて意味がありませんが、ヒープの割り当てに関連する特定の側面は、ヒープよりも明らかに遅いです。スタックの途中から物を削除できないために断片化できないスタックとは異なり、ヒープは断片化の影響を受けます。プログラムは、オブジェクトの割り当てを任意の順序で解除して、ヒープに「穴」を作成できます。より多くのメモリを要求する場合、アロケータは要求を満たすために適切な「穴」を検索する必要があります。
さらに、スタックベースの操作は、コンピューターのハードウェアによって高度に最適化されています。最後に、自動ストレージ(「スタック」の正式名称)に割り当てられたオブジェクトは、プログラムがアクセスする他のローカルに近接しているため、キャッシュされる可能性が高くなります。
ストレージに関してstatic
は、データメンバーにのみ適用されます。静的関数と静的メンバー関数は、キーワードの意味を再利用せずに、キーワードを再利用するだけです。静的ストレージ内のオブジェクトは1回だけ割り当てられるため、断片化の原因はありません。
割り当てが完了すると、3種類のストレージ(静的、動的、および自動)内のオブジェクトへのアクセス速度はほぼ同じ速度になります。
1)間接的な問題ではなく、メモリ管理の問題です。スタックにメモリを割り当てることは、スタックポインタを上に移動することです。ヒープへの割り当てには、適切なサイズのメモリセグメントを探し、断片化を考慮に入れることが含まれます。
2)静的メモリはプログラムへのメインエントリポイントの前に割り当てられるため、実際の実行時のオーバーヘッドはありません。すでに割り当てられているメモリへのアクセス速度は、メモリが割り当てられている場所に実際には依存しません。
スタックがヒープよりもはるかに高速である理由の1つは、局所性の原則によるものです。スタックに格納されたデータは連続した場所に配置されます。つまり、1つの変数が参照されると、隣接する情報が自動的にキャッシュに取り込まれます。ヒープに格納されているデータ(動的配列を除く)には、この利点はありません。