2010-11-25 7 views
2

私はクラスの "Dispose"がすべてのイベントをアンフックし、オブジェクトを参照するタイマーを処分することを確認するユニットテストを書いています。WeakReference.IsLive()がfalseになる前に完全なガベージコレクションの後に遅延がありますか?

WeakReference.IsLive()は、falseを返すと予想されるときにtrueを返します。

WeakReference.IsLive()が更新される前に完全なGCの後に遅延がありますか?

もしそうでなければ、私には繰り返し得られない結果を与えてくれる何かを考えてもらえますか?

WeakReference weekJobWatchDog = new WeakReference(jobWatchDog); 
jobWatchDog = null; 

// not collected before Dispose called due to timer and events etc 
GC.Collect(); GC.Collect(); 
Assert.IsTrue(weekJobWatchDog.IsAlive); 

((IDisposable)weekJobWatchDog.Target).Dispose(); 

// is now collected as Dispose unlocked all events and dispoed the timer 
GC.Collect(); GC.Collect(); 
Assert.IsFalse(weekJobWatchDog.IsAlive); // sometimes this fails, about 1 in 4 runs 

関連するが別の質問のためにもTesting Finalizers and IDisposable参照してください。

How can I write a unit test to determine whether an object can be garbage collected?は、GC.WaitForPendingFinalizers()を呼び出すことを含む解決策を持っていますが、GC.WaitForPendingFinalizers()を呼び出すのではなく、ディスパッチの仕組みを証明したいので、ファイナライザを実行する必要はありません。

+0

WaitForPendingFinalizersを呼び出そうとしましたか? – Henrik

+0

@Henrik、いいえ、私たちが待っているファイナライザを持っていないので、 –

答えて

0

これが問題だったことI持っていた:

あなたはSystem.Timers上のDispose()を呼び出すとき。 Win32タイマが破棄される前に、タイマに戻ることがあります。したがって、まだ管理されていないスペースには、タイマーを稼動させたままの「ルート」があります。時間は私のオブジェクトを生きていたイベントハンドラを持っていた。

これは非常に時宜に関連しているため、ほとんどの場合、TimerはGCedを取得し、私のオブジェクトも取得します。しかし、時には(例えば10回に1回)タイマーが生きているので、私のオブジェクトも生き続けるでしょう。

短いスリープ()は私のテストに100%時間を渡しますので、タイマーがそのオブジェクトを有効に保つことができないように、タイマーでイベントをアンフックしてから廃棄します。弱い参照のisLiveの各プロパティが参照であることを意味し、永遠にkaputされ、その値をチェックする必要はありませんつまり、falseを返す場合

How do I safely dispose a System.Timers.Timer?

0

Collectメソッドがブロックされていないので、私が推測しているのは、GCは、IsAliveをテストした時点でオブジェクトを収集していないと推測しています。

(そしてyou can only trust IsAlive when it returns falseことを忘れないでください。)

私は解決策は、あなたが待つために、独自の任意のファイナライザを持っていない場合でも、WaitForPendingFinalizersのようなものにブロッキング呼び出しする必要がありますと仮定します。 (私はあなたの代わりに使用することができ、他の適切なブロッキング方法があるかはわからない)

+0

私はいつもCollectメソッドがデフォルトでブロックされていると思っていました。 –

+1

@イアン:あなたが正しいかもしれないと思います。どちらの方法でも確認するための明確な文書は見つかりません。 GC自体は、(ワークステーションGCの非並行バージョンを実行している場合を除いて)コレクション全体の期間、必ずしもすべてのアプリケーションスレッドを停止するとは限りませんが、ここでは 'Collect 'メソッド*がブロックされています。たぶん専門家がいくつかの具体的な回答でチャイムすることができます... – LukeH

-2

参照してください。それが真を返すならば、それは参照かもしれないが生きているかもしれないことを意味しますが、強い参照にその値を取り込もうとするまで、実際には分かりません。 WeakReferenceが特定の適時性をもって無効にされることに頼るべきではなく、また実際に興味がない限り、その価値を取るべきではありません。 WeakReferenceのリストをクリーンアップし、死んだものを削除するようなことをしている場合、IsAliveプロパティはガベージコレクションに適格である可能性のあるものへの強い参照を作成することなく、リスト内の弱い参照のいずれがクリーンアップに適格なのかについて特に保証はないが、(1)記憶力の存在下でそのような適格性がより適時になる。 (2)記憶力がなければ、適時性は一般的に問題ではない。

関連する問題