2010-12-08 98 views
7

次のように指定します。GC.CollectとGC.WaitForPendingFinalizersを呼び出してデッドロックすることはできますか?

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

マルチスレッドとガベージコレクションモードを考慮して、WaitForPendingFinalizersでデッドロックが発生する状況は何ですか?

注:GC.Collectを呼び出してはいけない理由についての回答はありません。

+2

これは厳密に先験的な質問ですか、実際のデッドロック状況が発生していますか? (トラブルシューティングを行う場合は、ファイナライザメソッドのコードを投稿すると便利です)。 –

答えて

6
// causes a deadlock when built with release config and no debugger attached 
// building in debug mode and/or attaching the debugger might keep 
// badIdea alive for longer, in which case you won't see the deadlock 
// unless you explicitly set badIdea to null after calling Monitor.Enter 

var badIdea = new BadIdea(); 
Monitor.Enter(badIdea); 

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

// ... 

public class BadIdea 
{ 
    ~BadIdea() 
    { 
     lock (this) 
     { 
      // ... 
     } 
    } 
} 
1

Jeffrey Richterが記述したWaitForPendingFinalizersには、有名なデッドロックがあります。ここに示されています: http://haacked.com/archive/2005/04/12/neverlockthis.aspx

 
class MyClass 
{ 

private bool isDisposed = false; 

    ~MyClass() 
    { 
     lock(this) 
     { 
      if(!isDisposed) 
      { 
       // ... 
      } 
     } 
    } 
} 
... 
MyClass instance = new MyClass(); 

Monitor.Enter(instance); 
instance = null; 

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

が、それは正しくない(この)ロックを使用することによって引き起こされます。とにかく、これはWaitForPendingFinalizersがロックされている状況です。

1

GC.CollectGC.WaitForPendingFinalizersを呼び出すときに、あなたのFinalizeメソッド内の管理対象オブジェクトにアクセスしているない限り、あなたは、デッドロック状態のいずれかの種類を経験しないでしょう。 publicスコープを持つ他のオブジェクトのメソッドを呼び出すと、となる可能性があります。デッドロックを含む、予期しない結果につながる可能性があります。その理由は、他のオブジェクトのロックパターンを完全に制御できていないからです。ファイナライザメソッドがアクセスしようとしている間は誰でもロックすることができます。

さらに、finalizerで明示的にロックすると、が保証され、LukeHの答えが示すようにデッドロックが発生します。ジェフリー・リヒテルのオリジナル記事はhereです。

一般に、ファイナライザで管理されていないリソースを解放するだけで、デッドロックに関する懸念が緩和されるはずです。

+0

実際には、ファイナライズ可能なオブジェクトに他の管理対象オブジェクトへの参照を保持させると便利な場合があります。例えば、 'Bitmap'オブジェクトは高価であるため、数百の16x16アイコンを格納する必要のあるプログラムは、それぞれが64個のアイコンを保持できる16x1024ピクセルのビットマップを割り当てるクラスを定義し、それぞれが参照を保持するオブジェクトを返しますどの部分が「所有しているか」の指示とともにビットマップアロケータに渡す。そのような「ビットマップピース」オブジェクトが配置されるとき、アロケータは、より大きなビットマップのその部分を他の誰かに利用可能にすることができる。 – supercat

+0

大きなビットマップへの唯一の強い参照が「ビットマップピース」オブジェクト内にあったとしても、そのようなオブジェクトをすべて放棄すると、ビットマップに関連付けられた「ビットマップピース」オブジェクトの1つを除くすべてを破棄して、全体を割り当てたままにしておきますが、他の目的にはほとんど利用できません。ファイナライザをビットマップピースオブジェクトに追加すると、マスタオブジェクトは放棄されたピースを再利用することができます。もちろん、このようなコードは、デッドロックやその他のスレッドの問題を避けるために慎重に書かなければなりませんが、それでも役に立つ可能性があります。 – supercat

+0

私はこの答えや質問と何が関係しているのか分かりません。 @supercat –

関連する問題