17

C ++の変数はどこに保存されますか?

RAMまたはプロセッサのキャッシュの内部?

4

9 に答える 9

43

名前付き変数は次の場所に保存されます。

  • スタック上 (関数ローカル変数の場合)。
    C++ はこれを「自動ストレージ」1と呼び、実際に asm コール スタックである必要はなく、一部のまれな実装ではそうではありません。しかし、主流の実装ではそうです。
  • グローバルまたはstatic.
    C++ はこれを「静的ストレージ クラス」と呼びます。section .data、、、などにバイトを配置/予約することにより.bss、asmに実装されます.rodata

変数が で初期化されたポインターである場合int *p = new int[10];、ポインター変数pは上記のように自動ストレージまたは静的ストレージに格納されます。メモリ内のポイント先オブジェクトは次のとおりです。

  • newormallocなどで割り当てられたヒープ (C++ が動的ストレージと呼ぶもの) 上
    。「ヒープ」は、最新の OS / C++ 実装では単一の連続した領域ではありません。

C および C++ は自動ガベージ コレクションを実行せず、名前付き変数自体を動的ストレージ (「ヒープ」) に置くことはできません。動的ストレージ内のオブジェクトは、他のオブジェクトによってポイントされることを除いて、匿名です。その一部は適切な変数である可能性があります。(構造体またはクラス型のオブジェクトは、のようなプリミティブ型とは対照的にint、この無名オブジェクトで名前付きクラス メンバーを参照できます。メンバー関数では、それらは同一に見えます。)

これが、ローカル変数へのポインターまたは参照を (安全に/有用に) 返すことができない理由です。


もちろん、これはすべてRAMにあります。キャッシングは、パフォーマンスに目に見えて影響を与える可能性がありますが、ユーザー空間プロセスに対して透過的です。

コンパイラは、変数をレジスタに格納するようにコードを最適化する場合があります。これはコンパイラとコードに大きく依存しますが、優れたコンパイラは積極的にそうします。


脚注 1: 豆知識: autoC++03 以前と C では、自動 storage-class を意味していましたが、現在 (C++11) では型を推論します。

于 2008-10-23T17:22:29.060 に答える
17

一般的な C++ の場合、適切な答えは「コンパイラがそれらを配置することを決定した場所」です。何らかの方法でコンパイラに別の指示をしない限り、それ以外の仮定を行うべきではありません。一部の変数は完全にレジスターに格納でき、一部は完全に最適化されてどこかでリテラルに置き換えられる場合があります。一部のプラットフォームの一部のコンパイラでは、定数が実際に ROM に格納される場合があります。

「プロセッサのキャッシュ」に関する質問の部分は少し混乱しています。プロセッサがキャッシュを処理する方法を指示するためのツールがいくつかありますが、一般に、それはプロセッサの仕事であり、ユーザーには見えないはずです。キャッシュは、CPU の RAM へのウィンドウと考えることができます。ほとんどメモリ アクセスはキャッシュを経由します。

方程式の反対側では、未使用の RAM がほとんどの OS でディスクにスワップ アウトされることがあります。そのため、ある時点で変数が実際にディスクに保存されている可能性があります (ただし、可能性は低いです)。:-)

于 2008-10-23T17:48:56.477 に答える
13

変数は通常 RAM に保存されます。これは、ヒープ (例: グローバル変数、メソッド/関数内の静的変数) またはスタック (例: メソッド/関数内で宣言された非静的変数) のいずれかです。スタックとヒープはどちらも RAM であり、場所が異なるだけです。

ポインターは少し特殊です。ポインター自体は上記の規則に従いますが、ポインターが指すデータは通常、ヒープ ( で作成されたメモリ ブロック、 で作成されたmallocオブジェクトnew) に格納されます。それでも、スタック メモリを指すポインターを作成できますint a = 10; int * b = &a;。のメモリをb指し、スタックに格納されます。aa

CPU キャッシュに入る内容はコンパイラの制御を超えており、CPU は何をキャッシュするか、キャッシュする期間を自分で決定します (「このデータは最近使用されましたか?」または「データが使用されると予想されるか?」などの要因に応じて)。またすぐに? ")そしてもちろん、キャッシュのサイズも大きな影響を与えます。

コンパイラは、どのデータが CPU レジスタに入るかを決定することしかできません。レジスタアクセスはキャッシュよりも高速で、RAM よりもはるかに高速であるため、通常、連続して非常に頻繁にアクセスされる場合、データはそこに保持されます。特定のシステムの一部の操作は、実際にはデータがレジスターにある場合にのみ実行できます。その場合、コンパイラーは操作を実行する前にデータをレジスターに移動する必要があり、いつデータを RAM に戻すかを決定することしかできません。

コンパイラは常に、最も頻繁にアクセスされるデータをレジスタに保持しようとします。メソッド/関数が呼び出されると、呼び出された関数/メソッドがデータの取得元のメモリにアクセスしないことをコンパイラが確実に判断できない限り、通常はすべてのレジスタ値が RAM に書き戻されます。また、メソッド/関数の戻り時に、すべてのレジスタ データを RAM に書き戻す必要があります。そうしないと、新しい値が失われます。一部の CPU アーキテクチャでは戻り値自体がレジスタに渡されますが、それ以外の場合はスタック経由で渡されます。

于 2008-10-23T17:34:21.280 に答える
6

C++ の変数は、スタックまたはヒープに格納されます。

スタック:

int x;

ヒープ:

int *p = new int;

そうは言っても、どちらもRAMに組み込まれた構造です。

RAM の使用率が高い場合でも、Windows はこれをディスクにスワップできます。

変数に対して計算が行われると、メモリはレジスタにコピーされます。

于 2008-10-23T17:20:43.727 に答える
6

C++ はプロセッサのキャッシュを認識しません。

C++ またはその他の言語で書かれたプログラムを実行している場合、CPU は RAM の「一般的な」チャンクのコピーをキャッシュに保持します。これはハードウェア レベルで行われます。

CPU キャッシュを「その他」または「その他」のメモリと考えないでください。これは、RAM の一部のチャンクを近くに保持するための単なるメカニズムです。

于 2008-10-23T18:25:58.120 に答える
4

あなたは2つの概念を混同していると思います。1つは、C++言語が変数をメモリに格納する方法です。2つ目は、コンピューターとオペレーティングシステムがそのメモリをどのように管理するかです。

C ++では、変数はスタックに割り当てることができます。スタックは、プログラムで使用するために予約され、スレッドの開始時にサイズが固定されているメモリ、またはnewを使用してオンザフライで割り当てることができるダイナミックメモリです。コードの分析で許可されている場合、コンパイラーは、プロセッサー内のレジスターに変数を保管することも選択できます。これらの変数は、システムメモリを見ることはありません。

変数がメモリに格納された場合、OSとプロセッサチップセットが引き継ぎます。スタックベースのアドレスと動的アドレスはどちらも仮想です。つまり、いつでもシステムメモリに常駐している場合と常駐していない場合があります。インメモリ変数は、システムメモリに格納されるか、ディスクにページングされるか、プロセッサ上またはプロセッサの近くのキャッシュに常駐する可能性があります。したがって、そのデータが実際にどこにあるのかを知ることは困難です。プログラムがしばらくアイドル状態になっていない場合、または2つのプログラムがメモリリソースをめぐって競合している場合は、値をページファイルのディスクに保存し、プログラムが実行されるようになったときに復元できます。変数が実行中の作業に対してローカルである場合、最終的にシステムメモリにフラッシュバックされる前に、プロセッサキャッシュで数回変更される可能性があります。あなたが書いたコードは、これが起こったことを決して知りません。

于 2008-10-23T18:14:55.770 に答える
1

変数はさまざまな場所に保持でき、複数の場所に保持されることもあります。ほとんどの変数は、プログラムがロードされるときに RAM に配置されます。宣言された変数constが代わりに ROM に配置されることがあります。変数がアクセスされるたびに、変数がプロセッサのキャッシュにない場合、キャッシュ ミスが発生し、変数が RAM/ROM からキャッシュにコピーされる間、プロセッサが停止します。

中途半端な最適化コンパイラを使用している場合、ローカル変数はプロセッサのレジスタ ファイルに格納されることがよくあります。変数は、読み取りおよび書き込み時に RAM、キャッシュ、およびレジスタ ファイルの間を行き来しますが、コンパイラが不要と判断しない限り、通常は常に RAM/ROM にコピーを保持します。

于 2008-10-23T17:20:08.847 に答える
1

C++ 言語は、C++ プログラムの変数を介して 2 種類のメモリ割り当てをサポートしています。

静的割り当ては、静的変数またはグローバル変数を宣言するときに発生します。各静的変数またはグローバル変数は、固定サイズのスペースの 1 つのブロックを定義します。この領域は、プログラムの開始時 (exec 操作の一部) に一度割り当てられ、解放されることはありません。関数の引数やローカル変数などの自動変数を宣言すると、自動割り当てが発生します。自動変数のスペースは、宣言を含む複合ステートメントに入ると割り当てられ、その複合ステートメントを終了すると解放されます。自動ストレージのサイズは、さまざまな式にすることができます。他の CPP 実装では、定数でなければなりません。3 つ目の重要なメモリ割り当てである動的割り当ては、C++ 変数ではサポートされていませんが、ライブラリ関数で使用できます。動的メモリ割り当て

動的メモリ割り当ては、プログラムが実行中に情報を格納する場所を決定する手法です。必要なメモリの量、またはそれが必要であり続ける期間が、プログラムの実行前にはわからない要因に依存する場合、動的割り当てが必要です。

たとえば、入力ファイルから読み取った行を格納するブロックが必要になる場合があります。1 行の長さに制限がないため、メモリを動的に割り当てて、より多くの行を読み取るにつれてメモリを動的に大きくする必要があります。

または、入力データ内のレコードごとまたは定義ごとにブロックが必要になる場合があります。いくつになるかを事前に知ることはできないため、レコードまたは定義を読み取るたびに新しいブロックを割り当てる必要があります。

動的割り当てを使用する場合、メモリ ブロックの割り当ては、プログラムが明示的に要求するアクションです。領域を確保したい場合は関数やマクロを呼び出し、引数でサイズを指定します。スペースを解放したい場合は、別の関数またはマクロを呼び出して解放します。これらのことは、いつでも、何回でも行うことができます。

動的割り当ては CPP 変数ではサポートされていません。「動的」なストレージ クラスは存在せず、動的に割り当てられた領域に値が格納される CPP 変数は存在しません。動的に割り当てられたメモリを取得する唯一の方法はシステム コールを使用することであり、動的に割り当てられた領域を参照する唯一の方法はポインターを使用することです。あまり便利ではなく、動的割り当ての実際のプロセスにはより多くの計算時間が必要なため、プログラマは通常、静的割り当ても自動割り当ても機能しない場合にのみ動的割り当てを使用します。

たとえば、構造体 foobar を保持するための領域を動的に割り当てたい場合、動的に割り当てられた領域を内容とする構造体 foobar 型の変数を宣言することはできません。ただし、ポインター型 struct foobar * の変数を宣言して、スペースのアドレスを割り当てることができます。次に、このポインター変数で演算子「*」および「->」を使用して、スペースの内容を参照できます。

 {
   struct foobar *ptr
      = (struct foobar *) malloc (sizeof (struct foobar));
   ptr->name = x;
   ptr->next = current_foobar;
   current_foobar = ptr;
 }
于 2013-01-17T14:38:04.020 に答える
0

宣言方法に応じて、「ヒープ」または「スタック」に格納されます。

ヒープは、アプリケーションが使用できる動的データ構造です。

アプリケーションがデータを使用する場合、データが消費される直前に CPU のレジスタに移動する必要がありますが、これは非常に揮発性の一時的なストレージです。

于 2008-10-23T17:21:07.347 に答える