ウィキペディアでC#のエントリを読んでいて、次のようなものに出会いました。
管理メモリは明示的に解放できません。代わりに、自動的にガベージ コレクションが行われます。
自動メモリ管理を備えた言語では、手動管理さえ許可されていないのはなぜですか? ほとんどの場合、必要ないことがわかりますが、メモリが不足していて、GC がスマートであることに依存したくない場合に便利ではないでしょうか?
ウィキペディアでC#のエントリを読んでいて、次のようなものに出会いました。
管理メモリは明示的に解放できません。代わりに、自動的にガベージ コレクションが行われます。
自動メモリ管理を備えた言語では、手動管理さえ許可されていないのはなぜですか? ほとんどの場合、必要ないことがわかりますが、メモリが不足していて、GC がスマートであることに依存したくない場合に便利ではないでしょうか?
自動メモリ管理を備えた言語は、手動のメモリ管理では提供できない実質的なメモリの安全性を保証するように設計されています。
防止される問題には、次のものがあります。
free()
_free()
、他の場所で不正なアクセスにつながるfree()
割り当て関数の戻り値ではないポインターの呼び出し。たとえば、スタック上または配列またはその他の割り当ての途中にあるオブジェクトのアドレスを取得します。free()
dされているメモリへのポインターの逆参照さらに、自動管理により、GC がライブ オブジェクトを統合領域に移動するときにパフォーマンスが向上する可能性があります。これにより、参照の局所性が向上し、キャッシュのパフォーマンスが向上します。
ガベージ コレクションは、メモリ割り当てがエイリアスされないことを保証することにより、メモリ アロケータのタイプ セーフを強化します。つまり、メモリの一部が現在 type として表示されているT
場合、メモリ アロケータは (ガベージ コレクションを使用して) その参照が生きている間は常に を参照することを保証できますT
。より具体的には、メモリ アロケータがそのメモリを別の型として返さないことを意味します。
ここで、メモリ アロケータが手動free()
を許可し、ガベージ コレクションを使用する場合、メモリ アロケータは、指定したメモリがfree()
他の誰からも参照されないようにする必要があります。つまり、渡すfree()
参照がそのメモリへの唯一の参照であるということです。ほとんどの場合、これを任意に呼び出すと非常にコストがかかるためfree()
、ガベージ コレクションを使用するほとんどのメモリ アロケータでは許可されていません。
それが不可能だと言っているわけではありません。単一参照タイプを表現できれば、手動で管理できます。しかし、その時点で GC 言語の使用をやめるか、単に気にしない方が簡単です。
GC.Collect
ほとんどの場合、呼び出しは明示的なfree
メソッドを使用するよりも優れています。呼び出しfree
は、どこからも参照されないポインター/オブジェクト参照に対してのみ意味があります。free
これは、間違った種類のポインターを呼び出す可能性があるため、エラーが発生しやすいものです。
ランタイム環境が参照カウントの監視を行う場合、安全に解放できるポインターと解放できないポインターを認識できるため、解放できるメモリを GC に決定させることで、醜いバグのホール クラスを回避できます。GC
と の両方を使用したランタイム実装を考えることができます。単一のメモリ ブロックをfree
明示的に呼び出すfree
と、完全なメモリ ブロックを実行するよりもはるかに高速になる可能性がありますGC.Collect
(ただし、可能なすべてのメモリ ブロックを「手動で」解放するのが GC よりも高速であるとは期待しないでください)。しかし、C#、CLI (および Java のようなガベージ コレクターを備えた他の言語) の設計者は、ここでは速度よりも堅牢性と安全性を優先することに決めたと思います。
オブジェクトを手動で解放できるシステムでは、割り当てルーチンは、解放されたメモリ領域のリストを検索して、空きメモリを見つける必要があります。ガベージ コレクション ベースのシステムでは、すぐに使用できる空きメモリはヒープの最後になります。一般に、システムがヒープの途中にある未使用のメモリ領域を無視する方が、それらを割り当てようとするよりも高速で簡単です。
他の多くの回答は、GCがどのように機能するか、およびGCを提供するランタイムシステムに対してプログラミングするときにどのように考える必要があるかについての適切な説明を提供します。
GC言語でプログラミングするときに覚えておくべきトリックを追加したいと思います。ルールは「できるだけ早くポインタを落とすことが重要」です。ポインタをドロップするということは、使用しなくなったオブジェクトをポイントしなくなったことを意味します。たとえば、これは、変数をNullに設定することにより、一部の言語で実行できます。これは、ガベージコレクターへのヒントとして見ることができます。ただし、他にポインターがない場合は、このオブジェクトを収集しても問題ありません。
「GCがスマートであることに頼りたくない」という状況にある場合は、おそらく、タスクのフレームワークを間違って選択しました。.net では、GC を少し操作できます ( http://msdn.microsoft.com/library/system.gc.aspx )。Java ではわかりません。
GCの1つのタスクを開始するため、無料で呼び出すことはできないと思います。GC の効率は、最適な方法で実行し、決定したときに実行する場合、全体として何らかの形で保証されます。開発者が GC に干渉すると、全体的な効率が低下する可能性があります。
それが答えだとは言えませんが、頭に浮かぶのは、可能であればfree
、誤っfree
てポインター/参照を2倍にしたり、さらに悪いことに、フリーの後に1つを使用したりする可能性があるということです。これは、c#/java/etc などの言語を使用する主なポイントを無効にします。
もちろん、それに対する1つの可能な解決策は、free
参照によって引数を取りnull
、解放後にそれを設定することです。しかし、次のように渡すとどうなるでしょうかr-value
: free(whatever())
. r値バージョンのオーバーロードが可能だと思いますが、c#がそのようなことをサポートしているかどうかさえわかりません:-P.
結局、指摘されているように、同じオブジェクトへの複数の参照を持つことができるため、それでも不十分です。1 つを に設定null
しても、他のオブジェクトが現在割り当て解除されているオブジェクトにアクセスするのを防ぐことはできません。
興味深いことに、System.GC を介してガベージ コレクターにアクセスできます。ただし、私が読んだすべてのことから、GC 自体が管理できるようにすることを強くお勧めします。
DLL または COM オブジェクトなどのガベージ コレクションの問題に対処するために、サード パーティ ベンダーから次の 2 行を使用するようにアドバイスされたことがあります。
// Force garbage collection (cleanup event objects from previous run.)
GC.Collect(); // Force an immediate garbage collection of all generations
GC.GetTotalMemory(true);
とはいえ、内部で何が起こっているのかを正確に把握していない限り、System.GC を気にすることはありません。この場合、サードパーティ ベンダーのアドバイスにより、私が扱っていたコードに関する問題が「修正」されました。しかし、これが実際に壊れたコードの回避策だったのではないかと思わずにはいられません...
なぜ使用したいのfree()
ですか?割り当てを解除したい大量のメモリがあるとします。
これを行う 1 つの方法は、ガベージ コレクターを呼び出すか、システムが必要なときに実行させることです。その場合、メモリの大きなチャンクにアクセスできない場合は、割り当てが解除されます。(最近のガベージ コレクターはかなり賢いです。) つまり、割り当てが解除されていない場合でも、アクセスできる可能性があります。
したがって、ガベージ コレクターではなく、それを取り除くことができる場合free()
でも、何かがそのチャンクにアクセスできます (言語に概念がある場合は、弱いポインターを介してアクセスすることはできません)。ぶら下がっているポインター。
この言語は、二重解放や未割り当てのメモリを解放しようとすることから身を守ることができますが、ぶら下がりポインターを回避する唯一の方法は、 を廃止するfree()
か、その意味を変更して使用できなくすることです。
自動メモリ管理を備えた言語では、手動管理さえ許可されていないのはなぜですか? ほとんどの場合、必要ないことがわかりますが、メモリが不足していて、GC がスマートであることに依存したくない場合に便利ではないでしょうか?
free
ほとんどの場合、必要に応じて FFI を使用してマネージド VM の外部にアンマネージド メモリを割り当てたり解放したりできますが、ガベージ コレクションされた言語や VM の大部分では、機能を提供する意味はありません。
free
がガベージ コレクション言語にない主な理由は 2 つあります。
メモリの安全性に関して、自動メモリ管理の背後にある主な動機の 1 つは、不適切な手動メモリ管理によって引き起こされるバグのクラスを排除することです。たとえば、手動のメモリ管理free
で同じポインタを 2 回呼び出したり、誤ったポインタを使用して呼び出したりすると、メモリ マネージャー自体のデータ構造が破損し、プログラムの後半 (メモリ マネージャーが次に破損したデータに到達したとき) で非決定論的なクラッシュが発生する可能性があります。これは、自動メモリ管理では発生しませんが、公開するfree
と、このワームの缶が再び開かれます。
ポインターに関しては、このfree
関数は、ポインターによって指定された場所で割り当てられたメモリのブロックをメモリ マネージャーに解放します。ガベージ コレクションされた言語と VM は、ポインターを参照と呼ばれるより抽象的な概念に置き換えます。ほとんどの実稼働 GC は移動します。つまり、高レベル コードは値またはオブジェクトへの参照を保持しますが、VM は高レベル言語を認識せずに割り当てられたメモリ ブロックを移動できるため、メモリ内の基になる場所が変更される可能性があります。これはヒープを圧縮するために使用され、断片化を防ぎ、局所性を改善します。
free
したがって、GC を使用している場合に使用しない十分な理由があります。
手動管理は許可されています。たとえば、Ruby を呼び出すGC.start
と、解放できるものはすべて解放されますが、個別に解放することはできません。