GC.SuppressFinalize が呼び出されたオブジェクトはどうなりますか? これは、GC がそのようなオブジェクトのファイナライザー (デストラクタ) を呼び出さないことを意味することを理解しています。そうしないと、メモリリークが発生しますよね?
ファイナライズの目的を誤解しています。ファイナライズは、マネージド メモリではないリソースをクリーンアップするためのものです。
整数フィールドを含む参照型のオブジェクトがあるとします。その整数フィールドは、アンマネージ コードを呼び出してファイルを開くことによって取得されたファイルへのハンドルです。
他のプログラムがそのファイルにアクセスする可能性があるため、できるだけ早くファイルを閉じることをお勧めします。しかし、.NET ランタイムは、この整数がオペレーティング システムにとって特別な意味を持つことを認識していません。それはただの整数です。
通常、この問題を解決する方法は、オブジェクトを IDisposable を実装するものとしてマークし、処理が完了したらすぐにオブジェクトで "Dispose" を呼び出すことです。「Dispose」の実装により、ファイルが閉じられます。
ここでは特別なことは何もしていないことに注意してください。アンマネージ リソースをクリーンアップするメソッドを "Dispose" と呼び、破棄する必要があるオブジェクトが IDisposable を実装するのは単なる慣習です。ガベージ コレクションは、これについてまったく何も知りません。
ここで問題が発生します。誰かが Dispose を呼び出すのを忘れたらどうなるでしょうか。ファイルは永久に開いたままになりますか? (明らかに、プロセスが終了するとファイルは閉じられますが、プロセスが長時間実行されるとどうなりますか?)
この問題を解決するには、ファイナライザーを使用します。それはどのように機能しますか?
オブジェクトがガベージ コレクションの対象になると、ガベージ コレクターはオブジェクトをチェックして、ファイナライザーがあるかどうかを確認します。存在する場合は、ガベージ コレクションの代わりにファイナライザー キューに入れます。将来の特定されていない時点で、スレッドが実行され、キューが調べられ、すべてのオブジェクトに対して特別な「Finalize」メソッドが呼び出されます。その後、オブジェクトはファイナライズ キューから削除され、「ファイナライズ済みです」とマークされます。オブジェクトは再びコレクションの対象となるため、最終的にガベージ コレクターが実行され、ファイナライズ キューに置かれることなくオブジェクトが収集されます。
明らかに、"Finalize" と "Dispose" はしばしば同じことをする必要があります。
しかし今、別の問題が発生しています。オブジェクトを破棄するとします。今はファイナライズする必要はありません。ファイナライズにはコストがかかります。死んだオブジェクトを必要以上に長く生き続けます。したがって、伝統的にオブジェクトを破棄するとき、Dispose の実装はアンマネージ リソースを閉じるだけでなく、オブジェクトを「このオブジェクトは既にファイナライズされているため、再度ファイナライズしないでください」とマークします。こうすることで、ガベージ コレクターを騙して、オブジェクトをファイナライズ キューに置かないようにします。
それでは、具体的な質問に答えましょう。
GC.SuppressFinalize が呼び出されたオブジェクトはどうなりますか?
オブジェクトが死んでいる場合、ガベージ コレクターはオブジェクトをファイナライザー キューに入れることなく、単にオブジェクトのメモリを再利用します。
これは、GC がそのようなオブジェクトのファイナライザーを呼び出さないことを意味することを理解しています
GCがファイナライザーを呼び出すことはありません。ファイナライザー スレッドは、ファイナライザーを呼び出す唯一のものです。
これらのオブジェクトが実際に破壊されるのはいつですか?
「破壊された」の意味が明確ではありません。「ファイナライザーはいつ実行されますか?」という意味であれば、ファイナライズを抑制すると言ったので、答えは「決して」です。「マネージド ヒープ内のメモリが再利用されるのはいつですか?」という意味であれば、答えは「ガベージ コレクターによってオブジェクトが無効であると識別され次第」です。オブジェクトはファイナライザー キューによって保持されないため、通常よりも早く発生します。