3

デストラクタは、オブジェクトが保持しているアンマネージ リソースのみを解放する必要があり、他のオブジェクトを参照するべきではありません。管理参照しかない場合は、デストラクタを実装する必要はありません (実装すべきではありません)。これは、管理されていないリソースを処理する場合にのみ必要です。デストラクタを使用するとコストがかかるため、管理されていない貴重なリソースを消費するメソッドにのみ実装する必要があります。

-- C++ プログラマー向けの C# のトップ 10 トラップ

この記事ではこれについて詳しく説明していませんが、C# でデストラクタを使用すると、どのようなコストが発生するのでしょうか?

注: GC と、信頼できるタイミングでデストラクタが呼び出されないという事実については知っていますが、それ以外に何かありますか?

4

4 に答える 4

8

ファイナライザー (C++ デストラクタとの違いを強調するために、デストラクタよりもその用語を好みます) を持つすべてのオブジェクトは、ファイナライザ キューに追加されます。これは、削除する前に呼び出す必要があるファイナライザーを持つオブジェクトへの参照のリストです。

オブジェクトがガベージ コレクションの対象になると、GC はそれがファイナライザー キューにあることを検出し、参照を freachable (f-reachable) キューに移動します。これは、ファイナライザーのバックグラウンド スレッドが各オブジェクトのファイナライザー メソッドを順番に呼び出すために通過するリストです。

オブジェクトのファイナライザーが呼び出されると、そのオブジェクトはファイナライザー キューに存在しなくなるため、GC が削除できる通常のマネージド オブジェクトになります。

これはすべて、オブジェクトにファイナライザーがある場合、少なくとも 1 回のガベージ コレクションを経てから削除されることを意味します。これは通常、オブジェクトが次のヒープ世代に移動されることを意味します。これには、実際にメモリ内のデータをあるヒープから別のヒープに移動することが含まれます。

于 2009-03-05T01:51:49.023 に答える
6

これがどのように機能するかについて私が見た中で最も広範な議論は、Joe Duffy によって行われました。想像以上に詳細です。

それに続いて、これを日常的に行うための実用的なアプローチをまとめました - コストについてではなく、実装についてです。

于 2009-03-05T01:45:49.443 に答える
3

Guffa と JaredPar は詳細をかなりよくカバーしているので、C# 言語仕様では残念ながらファイナライザーまたはデストラクタを呼び出しているため、ファイナライザーまたはデストラクタについてやや難解なメモを追加します。

覚えておくべきことの 1 つは、ファイナライザー スレッドがすべてのファイナライザーを順番に実行するため、ファイナライザーでデッドロックが発生すると、残りの (および将来の) ファイナライザーがすべて実行できなくなることです。これらのインスタンスはファイナライザーが完了するまで収集されないため、デッドロックされたファイナライザーもメモリ リークを引き起こします。

于 2009-03-05T02:24:10.523 に答える
0

Guffaは、ファイナライザーのコストの要素を非常にうまくまとめています。Javaでのファイナライザーのコストに関する最近の記事があり、これもいくつかの洞察を提供します。

GC.SuppressFinalizeを使用してファイナライザーキューからオブジェクトを削除することにより、.netのコストの一部を回避できます。私は記事に基づいて.netでいくつかの簡単なテストを実行し、ここに投稿しました(ただし、焦点はJava側にはるかにあります)。


以下は結果のグラフです-それは実際には最高のラベルを持っていません;-)。「Debug=true / false」は、空のファイナライザーと単純なファイナライザーを指します。

~ConditionalFinalizer()  
{  
    if (DEBUG)  
    {  
        if (!resourceClosed)  
        {  
            Console.Error.WriteLine("Object not disposed");  
        }  
        resourceClosed = true;  
    }  
} 

「Suppress=true」は、GC.SuppressFinalizeがDiposeメソッドで呼び出されたかどうかを示します。

概要

.netの場合、GC.SuppressFinalizeを呼び出してファイナライザーキューからオブジェクトを削除すると、オブジェクトをキューに残すコストの半分になります。

于 2009-03-05T04:58:17.860 に答える