4

これらは主にコンパイラの設計に関する質問です。コンパイラがこれをコンパイルするとき、例えば:

int * pData = new int[256];

メモリはオンザフライでどのように割り当てられますか?コンパイラは、メモリを割り当てるOSルーチンを呼び出しますか、それともメモリを割り当てる関数をコンパイルしますか?

また、あなたがこのようなものを書くとき:

if (x == 5)
    int y;

実行時にメモリが割り当てられないため、プログラムのデータセグメントでデータがある程度のスペースを占めると想定しています。コンパイラは実行時にブランチが実行されるかどうかを実際に判断できないため、int y;実行されるかどうかに関係なく、変数用にメモリが予約されていますかint y;?そして、それが関係なく予約されている場合、実行される場合とされない場合があるブロック内の変数をmem allocする方が、メモリ効率が高くなりませんか?

ooありがとう

4

7 に答える 7

6

最初の質問の場合new:例のように、コンパイラーがオペレーターに遭遇した場合:

int * pData = new int[256];

次のようなコードを効果的に出力します。

int *pData = reinterpret_cast<int*>(::operator new(256 * sizeof(int)));
// the compiler may also choose to reserve extra space here or elsewhere to
// "remember" how many elements were allocated by this new[] so delete[] 
// can properly call all the destructors too!

コンストラクターを呼び出す必要がある場合は、それも発行されます(この例では、コンストラクターは呼び出されないと思います)。

operator new(std::size_t)は標準ライブラリによって実装される関数であり、常にではありませんが、多くの場合、呼び出しに要約されmallocます。

mallocOSにメモリを要求するには、システムコールを実行する必要があります。OSアロケータは通常、より大きな固定サイズのメモリブロックで動作mallocするため、現在のメモリを使い果たした場合にのみ、毎回この呼び出しを行う必要はありません。


2番目の質問の場合:ローカル変数の場合、それは実際にはコンパイラー次第です。この規格では、スタックについては言及されていません。ただし、ほとんどの場合、共通のOSを実行し、共通のコンパイラを使用している共通のアーキテクチャを使用しています:-)。

したがって、一般的なケースでは、コンパイラは通常、スタックを適宜調整するか、可能であればレジスタを予約することにより、すべてのローカル変数の関数呼び出しの開始時にスペースを予約します(レジスタははるかに高速であるため、推奨される選択肢です)。

次に(C ++では)、変数が検出されると、コンストラクターを呼び出します。理論的には、必要に応じてスタックを調整できますが、これは正しくて効率が悪いことを証明するために複雑になります。通常、スタックスペースの予約は単一の命令であるため、一度にすべてを予約するのが非常に最適です。

于 2011-04-04T20:56:02.013 に答える
2

メモリはオンザフライでどのように割り当てられますか?コンパイラは、メモリを割り当てるOSルーチンを呼び出しますか、それともメモリを割り当てる関数をコンパイルしますか?

ほとんどの実装では、これら2つの組み合わせのビットです。通常、プロセスにメモリのブロックを提供するために使用されるオペレーティングシステムサービスがあります。また、ランタイム内のコード、またはアプリケーション内でこれらのメモリのブロックをよりきめ細かいスケールで管理する標準ライブラリもあります。

「inty;」であるかどうかに関係なく、変数用に予約されているメモリです。実行されますか?そして、それが関係なく予約されている場合、実行される場合とされない場合があるブロック内の変数をmem allocする方が、メモリ効率が高くなりませんか?

通常、no-適切なコードが実行された場合にのみスペースyが割り当てられます。自動ストレージクラスを持つ変数は通常スタック上にあるため、スタックポインターを変更するのと同じくらい簡単に、変数用のスペースを作成できます。とは言うものの、この場合、コンパイラーはほとんど何でも実行できるので、ツールチェーンからの出力を検査することが確実に知る唯一の方法です。

于 2011-04-04T20:51:04.160 に答える
1

ローカル変数(int y)はスタックに割り当てられます。

同じことがポインタにも当てはまりますが、「new」-ed式は、通常、ある種のmalloc呼び出しを介してヒープに割り当てられます。正確なメソッドとヒープレイアウトは実装によって定義されます。

データセグメントには、グローバル静的データのみが含まれます。

例のintyは使用されていないため、最適化されます。

たとえばC#とは異なり、C ++では変数のスコープを縮小できないため、短命のローカルを{SomeClass y; }が役立つ可能性があるため、早期に破棄されます

ただし、単純な型(intなど)の場合、そのような制限は存在しないと確信しています。これらの型のデストラクタは存在しないためです。

于 2011-04-04T20:51:03.557 に答える
1

2番目の質問に関しては、条件付きコードのその変数は自動変数です。通常、それらはスタックに割り当てられます。この場合、優れたコンパイラーは、読み取りや書き込みが行われることはなく、スタックにスペースを割り当てる必要さえないことに気付くでしょう。

于 2011-04-04T20:51:59.737 に答える
0

これは、2番目の例のコンパイラに実際に依存します。そのため、volatileキーワードがあります(変数を変更するアドレスにマップする場合)。または、警告が表示される場合もありますが、プログラムに含まれると確信しています。 (ハック的な理由でメソッドのスタックサイズを増やしたい場合があります)。本質的に最初の例は、malloc(256 * sizeof(int))を呼び出し、そのセグメントへのポインターを返します。

于 2011-04-04T20:51:24.457 に答える
0

ケース1:OSルーチンを呼び出して、ヒープにメモリを割り当てます。OSがメモリを管理します。

ケース2:これはスタックに割り当てられます。スタックはプロセスに事前に割り当てられ、ローカル変数と関数の引数に使用されます。

于 2011-04-04T20:51:35.743 に答える
0

最初の質問の場合:

コンパイラは、関数を呼び出すコードを生成します。この関数operator newは、通常malloc、Cランタイムライブラリから呼び出します。このライブラリは、ある時点でカーネルモードに切り替わり、最終的にカーネルモードに切り替わるOS固有のライブラリを呼び出します。プロセスにメモリを割り当てます。

いずれにせよ、コンパイラが独自のプログラム用に生成するネイティブコードは、それ自体では割り当てを行いません。

2番目の質問の場合:

のメモリint yはスタックに割り当てられます。条件が真であるかどうかに関係なく、最も単純で最適化されていない場合、スタックスペースの割り当ては、コントロールが関数に入るたびに発生します。

スタック割り当ては、割り当てられるスペースの量に関係なく同時にかかるいくつかのレジスタ操作であり、関数が戻るとすぐにメモリが再利用されるため、ここでは「メモリの占有」の問題はありません。

于 2011-04-04T20:53:01.480 に答える