3

私はマネージ言語から直接始めましたが、C++ の経験はほとんどないため、この質問は基本的すぎるかもしれません。

.net のようなマネージ言語では、GC によってメモリが解放されます。私が読んだところによると、C++ ではこれは delete を呼び出すことによって行われます。しかし、それはメモリを解放するために何をしますか? メモリ位置のすべてのビットをゼロに設定しますか? それとも、別の方法でメモリが再利用可能であることをオペレーティング システムに伝えますか?

更新:私は以前にこれを経験しており、GCが何をするかを知っています。しかし、それは私の質問ではありません。GC がどのように機能するかを尋ねようとしているわけではありません。私が理解しようとしているのは、一部のメモリが空いていることをどのように伝えるのですか?

4

6 に答える 6

5

delete次の 3 つの異なることを行います。

  1. オブジェクト (または の場合は配列内のすべてのオブジェクト) のデストラクタを実行しますdelete[]

  2. オブジェクトによって以前に使用されたメモリのチャンクを空きとしてマークします。

  3. 可能であれば、他のプログラムが使用できるようにメモリのチャンクが解放されていることをオペレーティング システムに通知します。

あなたの質問は#2と#3を合わせたものですが、それらは非常に異なるものです. 2 番目の仕組みを理解するには、オペレーティング システムによって提供される (通常は) 単一の「ヒープ」が、さまざまなサイズの小さなチャンクに分割されていることを思い出してください。を使用してメモリのチャンクを割り当てるとnew、ヒープの以前に解放された部分へのポインターが取得され、ランタイムは必要な記録を実行して、その領域をそれ以上の割り当てに使用できないものとしてマークします。delete逆の場合: 領域を再度使用可能としてマークするブックキーピングを実行し、オプションで隣接する空き領域と合体させて断片化を減らします。の後続の呼び出しでnewは、返される空きメモリを探すときにその領域が考慮されます。

つまり、メモリの割り当てが解除されたときにメモリがどうなるかを尋ねるのは間違っています。本当の魔法は簿記の領域で起こります! ジェネリック アロケーターの実装については、Google で malloc の実装を検索してください。

#3に関しては、これはオプションのステップであり、多くの場合実行できません. 割り当てられたヒープの最後にたまたま存在する解放されたメモリを「返す」ことだけが可能です。大きな地域の後に配置された単一の割り当ては、ギブバックの可能性を排除します。

于 2013-07-06T21:08:34.137 に答える
1

いいえ、ポインターを削除しても、バイトはゼロに設定されません。もちろん標準にはありませんが、パフォーマンスのオーバーヘッドが発生し、深刻な実装では気にせず、メモリが複雑なオブジェクト (フロート、オブジェクト、文字列など) に使用されている場合は意味がありません。

いつでもお試しいただけます。int へのポインターを宣言し、整数を書き込み、ポインターを削除します。次に、削除されたポインターの内容を再度読み取ります。同じ内容ですか?

int *ptr = new int;
*ptr = 13;
cout << "Before delete: " << *ptr << endl;
delete ptr;
cout << "After delete: " << *ptr << endl;

はい、おそらくそうなるでしょう。しかし、ptr はそこにあるダングリング ポインターにすぎません。メモリはシステムに返されており、メモリを再度割り当てると使用可能になります。別の int* を割り当てると、ptr が指している可能性があります。指していました。

于 2013-07-06T20:28:39.427 に答える
1

ガベージ コレクションは単なる自動メモリ管理です (何もする必要はありませんdelete。システムが処理してくれます)。メモリの場所を 0 に設定するかどうかについては 100% ではありませんが、そうではないと思いますdelete。C++ を使用している場合はそうではなく、スペースをストレージに使用できるようにするだけです。すべてにゼロを書き込むことは、はるかに非効率的であり、必要ありません。これをより完全に説明するのに役立つリンクを次に示します。

C# でガベージ コレクションとスコープはどのように機能しますか?

http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

于 2013-07-06T01:02:10.777 に答える
1

いいえ、ビットをゼロに設定しません。非常に簡単な説明では、

まず、ガベージ コレクターは、どのオブジェクトがアクセスできなくなったか (「到達不能」) ではなく、どのオブジェクトがまだアクセス可能または到達可能であるかを判断する必要があります。これは、すべてのオブジェクトルートを単純にリストすることによって行われます。ルートは、参照オブジェクト (ヒープ上のオブジェクト) へのポインターを含むメモリの場所です。次に、再帰的に、ルートによって参照されるすべてのオブジェクト、または既に到達可能としてフラグが設定されているオブジェクトのフィールドまたはプロパティによって参照されるすべてのオブジェクトに「到達可能」としてフラグを立てます。
根には4種類あります。

  1. 参照オブジェクトを含む静的変数
  2. 現在アクティブなスレッドのスタック上のオブジェクトを参照します。
  3. メソッド パラメータの参照型
  4. CPU レジスタが指すオブジェクトを参照します。

App Domain 内の任意のコードから引き続きアクセスできる (到達可能な) 参照オブジェクトを特定した後、まだ到達可能なすべてのオブジェクトを取得し、それらの間の物理メモリにギャップがある場合は、それらの一部を移動して「最適化」します。それらがすべて連続するように、「終了」または「使用済み」メモリを表すポインタを、この新しい圧縮された最適化されたリストの最後に設定します。新しくインスタンス化されたオブジェクトのすべての新しいメモリ割り当ては、このポインタ位置の直後のメモリから割り当てられます。

到達可能なオブジェクトが使用するメモリにギャップがない場合は、ポインタをリスト内の最後の到達可能なオブジェクトの最後にリセットするだけです。

于 2013-07-06T01:04:11.897 に答える
1

各アプリケーション内では、動的メモリは「ヒープ」によって管理されます。コードがメモリ ブロックを要求すると、ヒープ マネージャーにメモリ ブロックを割り当てるように要求し、アプリケーションがそのメモリ ブロックを解放すると、それをヒープ マネージャーに返します。従来のアプリケーションでは、割り当てた各メモリを明示的に返す必要があります。そうしないと、最終的にメモリ不足になります。

C# や Java などの言語では、ランタイムがガベージ コレクターを提供します。ガベージ コレクタは、「到達不能」なメモリ ブロックを自動的に識別して解放します。読み取り不能なメモリ ブロックは、どの変数からも参照されなくなったブロックです。たとえば、メモリのブロックを指すグローバル変数 p1 がある場合、p1 はグローバルであるため、コード内のどこからでも参照でき、常に到達可能です。したがって、ガベージ コレクターによって解放されることはありません。一方、関数 Foo の 1 つにローカル変数 p2 がある場合、変数 p2 は Foo が返された後に到達できなくなります。ガベージ コレクターは、そのような変数を識別し、それらが指すメモリ ブロックを解放することができます。

アプリケーション/ガベージ コレクターがヒープと対話すると、ヒープは OS に追加のメモリを要求するか、OS に返すかを決定する場合があります。OS は、異なるプロセスからのこれらすべてのメモリ要求を管理し、実際の物理メモリを異なるプロセスに割り当てる方法を決定します。

于 2013-07-06T01:07:12.570 に答える