38

私は C# を (Java と C++ のバックグラウンドから) 学習するのが初めてで、手動のガベージ処理について質問があります。C# でオブジェクトを手動で破棄することさえ可能ですか? インターフェースについては知っていIDisposableますが、私が書いていないクラスを扱っていて、それを実装していないとしますか? .Dispose()メソッドがないため、 andusing { }は out であり、.Finalize常に either protectedor privateso もオプションではありません。

(この場合、C# で可能なことを学ぼうとしているだけです。他のすべてが失敗した場合は、架空のクラスを継承して、IDisposable を実装できると思います。)ImNotDisposable

4

8 に答える 8

36

.Net オブジェクトを手動で破棄しません。それが、管理された環境であることのすべてです。

実際、オブジェクトが実際に到達可能である場合、つまり、破棄するオブジェクトを GC に伝えるために使用できる参照がある場合、そのオブジェクトを収集することは不可能になります。GC は、まだ到達可能なオブジェクトを収集することはありません。

あなたができることはGC.Collect()、一般的なコレクションを強制するために呼び出すことです。ただし、これはほとんど良い考えではありません。

代わりに、管理されていないリソースを使用せず、プログラム内の他のオブジェクトからアクセスできないオブジェクトは、すぐに破棄されると単純に見なす方がよいでしょう。これが起こらないことはわかっていますが、この時点では、オブジェクトは他のオブジェクトと同様にメモリのブロックにすぎません。あなたはそれを取り戻すことはできず、最終的には収集されるので、あなたにとっては死んでいるかもしれません.

についての最後の注意事項IDisposable。ソケット、データベース接続、gdi オブジェクトなど、および時折のイベント/デリゲート サブスクリプションなど、アンマネージリソースをラップする型に対してのみ使用する必要があります。

于 2009-12-31T21:59:35.787 に答える
9

オブジェクトに到達できない場合は、呼び出すことができGC.Collect()、オブジェクトは破棄されます。の概念はIDisposableCLR とは関係なく、ほとんどの場合、追加の破棄ロジックを実行するために実装するユーザー コード用です。オブジェクトで Dispose() を呼び出しても、オブジェクト自体がメモリから解放されることはありませんが、このオブジェクトが参照するすべてのリソースが破棄される可能性があります。

私が言ったことはこれを達成するための方法ですが、99.9999% のアプリケーションでは、アプリケーションのパフォーマンスを改善する代わりに低下GC.Collect()させることが多いため、決して呼び出してはならないことを付け加えておきます。

于 2009-12-31T21:57:31.290 に答える
8

ガベージコレクションをトリガーすることはできますが(ファイナライズ可能なオブジェクトがどの世代にあるかわからないため、すべての世代に対してGCをトリガーする必要があります)、必ずしも特定のオブジェクトのファイナライズを強制することはできません。ガベージコレクタがどのように機能するかについての仮定にのみ依存することができます。

さらに、ファイナライズは独自のスレッドで行われるため、ガベージコレクションをトリガーした後にWaitForPendingFinalizersを呼び出す必要があります。

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();

他の人が指摘したように、これは実際にアプリケーションのパフォーマンスを損なう可能性があります。これは、GCを不必要に呼び出すと、短命のオブジェクトをより高い世代に昇格させる可能性があり、収集に費用がかかり、収集の頻度が低くなるためです。

一般的に、ファイナライザー(デストラクタ)を実装し、IDisposableを実装しないクラスは嫌われます。また、IDisposableを実装するものはすべて、そのファイナライザロジックを呼び出し、ガベージコレクションでのファイナライズを抑制している必要があります。

ジェフ・リクターは最近、ガベージコレクションが発生したときに通知を受け取るためのちょっとしたトリックを投稿しました。

リコマリアーニ(MSFT)によるガベージコレクターの基本とパフォーマンスのヒントに関する別の素晴らしい記事

于 2009-12-31T22:06:00.743 に答える
7

いいえ、特定のオブジェクトを破壊することはできません。

破棄するオブジェクトを探すガベージ コレクターを呼び出すことは可能ですが、ほとんどの場合、良い考えではありません。

于 2009-12-31T21:58:36.577 に答える
4

破棄したい変数がスコープ外になった後にガベージ コレクターを強制的に実行することもできますが、ガベージ コレクターは独自の作業を行うために残した方が効率的であるため、通常はそうしたくありません。

ガベージ コレクションの強制はGC.Collectで実行できますが、実行しないでください。.NET 開発者としての 10 年間、私は .NET を必要としたことはありません。

于 2009-12-31T21:59:54.420 に答える
2

決定論的な方法でオブジェクトを破棄することはできません。CLRは、フラグが立てられたオブジェクトがいつ再利用されるかを決定します。つまり、オブジェクトに再利用のフラグを立てて、管理対象リソースと非管理対象リソースを(IDisposableパターンを実装することにより)廃棄できるように整理できますが、メモリが解放される実際の時間はCLR次第です。これは、実際に何かを削除してリリースされるC++とは異なります。

于 2009-12-31T22:01:18.190 に答える
2

「C++削除のように」オブジェクトを手動で破棄することはできません。実行できるのは、オブジェクトが取得した排他的リソースをすべて閉じ、このオブジェクトへのすべての参照をnullにすることです。これにより、GCはオブジェクトを収集でき、GCを呼び出さないでください。 .Collect()を自分で使用すると、メモリからオブジェクトを安全に収集するために他のすべてのスレッドを一時停止する必要があるため、GCプロセスはコストがかかります。したがって、GCを信頼するだけで、必要に応じて開始されます。

于 2009-12-31T22:02:15.523 に答える