C#デストラクタ(別名:ファイナライザ)にかかる費用は?
-
03-07-2019 - |
質問
デストラクタは、オブジェクトが保持しているアンマネージリソースのみを解放し、他のオブジェクトを参照しないようにします。参照のみを管理している場合は、デストラクタを実装する必要はありません(実装すべきではありません)。これは、管理されていないリソースの処理にのみ必要です。 デストラクタを使用するには多少のコストがかかるため、管理されていない貴重なリソースを消費するメソッドにのみこれを実装する必要があります。
この記事ではこれ以上詳しく説明していませんが、C#でデストラクタを使用するとどのようなコストが発生しますか?
注: GCと、デストラクタが信頼できる時間に呼び出されないという事実を知っています。それはともかく、他に何かありますか?
解決
ファイナライザを持つオブジェクト(C ++デストラクタとの違いを強調するために、デストラクタよりもこの用語を好む)は、ファイナライザキューに追加されます。これは、オブジェクトを削除する前に呼び出す必要のあるファイナライザーを持つオブジェクトへの参照のリストです。
オブジェクトがガベージコレクションの準備ができると、GCはそのオブジェクトがファイナライザキューにあることを検出し、参照をfreachable(f-reachable)キューに移動します。これは、各オブジェクトのファイナライザメソッドを順番に呼び出すためにファイナライザバックグラウンドスレッドが通過するリストです。
オブジェクトのファイナライザが呼び出されると、オブジェクトはファイナライザキューにないため、GCが削除できるのは単なる通常の管理対象オブジェクトです。
これはすべて、オブジェクトにファイナライザがある場合、削除される前に少なくとも1つのガベージコレクションが存続することを意味します。これは通常、オブジェクトが次のヒープ世代に移動されることを意味し、実際にはメモリ内のデータをあるヒープから別のヒープに移動します。
他のヒント
これまでで最も広範な議論このすべての動作がどのようにジョー・ダフィーによって行われたかについて見ました。想像以上に詳細があります。
その後、をまとめました日常的にこれを行うための実用的なアプローチ-コストについてはより少なく、実装についてはより多く。
GuffaとJaredParは詳細をかなりよくカバーしているので、C#言語仕様では残念ながらそれらを呼び出しているので、ファイナライザーまたはデストラクタについて少し難解なメモを追加します。
留意すべきことの1つは、ファイナライザスレッドがすべてのファイナライザを順番に実行するため、ファイナライザのデッドロックにより、残りの(および将来の)ファイナライザの実行が妨げられることです。これらのインスタンスは、ファイナライザが完了するまで収集されないため、デッドロックされたファイナライザもメモリリークを引き起こします。
この記事では、問題について詳しく説明します。 http:// msdnのように、簡単なSO投稿で要約するのは非常に困難です。 microsoft.com/en-us/magazine/bb985010.aspx
Guffa は、ファイナライザーのコストの要因を非常にうまくまとめています。 Javaのファイナライザのコストについての最近の記事があり、これもいくつかの洞察を与えています。
.netのコストの一部は、GC.SuppressFinalizeを使用してファイナライザーキューからオブジェクトを削除することで回避できます。記事に基づいて.netでいくつかのクイックテストを実行し、こちら(ただし、焦点はJava側にはるかにあります)。
以下は結果のグラフです-実際には最高のラベルがありません;-)。 " Debug = true / false"空対単純なファイナライザを指します:
~ConditionalFinalizer()
{
if (DEBUG)
{
if (!resourceClosed)
{
Console.Error.WriteLine("Object not disposed");
}
resourceClosed = true;
}
}
" Suppress = true" DiposeメソッドでGC.SuppressFinalizeが呼び出されたかどうかを示します。
概要
.netの場合、GC.SuppressFinalizeを呼び出してオブジェクトをファイナライザキューから削除すると、オブジェクトをキューに残すコストの半分になります。