- - PR -
GC.WaitForPendingFinalizersについて
1
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2009-02-13 09:59
ASP.NET 2003で、webアプリを開発しています。
負荷試験にて、トップページに毎秒1件のアクセスを実施したところ、 メモリの使用量が右上がりに増えていきました。 トップページのロード処理の最後に GC.Collect() GC.WaitForPendingFinalizers() を追記したところ、 メモリの使用量は安定しましたが、 GC.WaitForPendingFinalizers() の処理で、時間が掛かってしまうようになりました。 GC.WaitForPendingFinalizers() はGC.Collect()が完了するまで待機する、という認識で 正しいでしょうか? GC.WaitForPendingFinalizers() を記述しなかった場合、GC.Collect()は効果があるのでしょうか? 以上です。ご教授の程、よろしくお願い致します。 | ||||||||||||||||
|
投稿日時: 2009-02-13 11:15
> GC.WaitForPendingFinalizers()
> はGC.Collect()が完了するまで待機する、という認識で > 正しいでしょうか? GC が回収したオブジェクトの内、ファイナライザを実行する必要のあるオブジェクトは、F リーチャブルキューという特別な領域に置かれます。そして、専用のスレッドでファイナライザが順番に実行されます。 WaitForPendingFinalizers メソッドは、この F リーチャブルキューが空になるまで待機するためのメソッドです。 > GC.WaitForPendingFinalizers() > を記述しなかった場合、GC.Collect()は効果があるのでしょうか? WaitForPendingFinalizers を呼び出すかどうかに関わらず、回収自体は行われます。 メモリの使用量や処理時間については、 WaitForPendingFinalizers を呼び出す場合と呼び出さない場合で実際に比較してみれば良いです。 ただ、「メモリの使用量が右上がりに増えた」とのことですが、それで実際にメモリ不足やら断片化の問題が発生していないのなら、 GC.Collect を行う必要はないのではないでしょうか。 GC は必要に応じて勝手に回収してくれます。下手に強制実行するとパフォーマンスが落ちる可能性があります。 _________________ C#と諸々 | ||||||||||||||||
|
投稿日時: 2009-02-13 11:40
それなりにちゃんと設計して作ってれば、メモリ使用量は上限があるはずです。
GCは必要がなければ実行されません。なので、右肩上がりになっててもそれは解放する必要がないからでしょう。 逆に、無計画に GC.Collect してしまうと、不必要なジェネレーション昇格が発生し、本来なら解放されやすいオブジェクトが解放されにくくなります。 | ||||||||||||||||
|
投稿日時: 2009-02-14 14:55
私もそう思っているのですが、ジェネレーション指定のない GC.Collect は、全てのジェネレーションを回収しますよね。ということは、「本来なら解放されやすいオブジェクトが解放されにくくな(る)」ということは、ないのでは? (今回の件では Page.Load イベントに GC.Collect を書いているため、自動回収が必要ないくらい頻繁に手動回収が実行されるという前提です。) | ||||||||||||||||
|
投稿日時: 2009-02-15 13:37
こんにちは。
すこし補足させていただくと 「ジェネレーション指定のない GC.Collect は、全てのジェネレーションのオブジェクトを対象に使用されていないかチェックし、もし使われていなければそのメモリを回収します」 でしょうか。
CLRの自動回収は常にフルGCを行うわけではありませんよね。 [追記] (以下、質問者の方へ) [/追記] なぜ常にフルGCをしないか(つまり、ジェネレーション別にガベージコレクトしているか)というと、一つには (Microsoft .NET Framework の自動メモリ管理 Part IIより抜粋)
という前提があるからです。 さらに、
不用意にGC.Collectを呼び、ジェネレーションを昇格させてしまうということは、 本来なら新しい(短命な)オブジェクトとされなければいけないものを、古いオブジェクトとして誤認させてしまう こともあるということです。 よほどパフォーマンスの改善が見込まれると確証のない限り、 手動でGC.Collectは呼び出さないほうが(CLRの自動回収に任せたほうが) 良いのではないでしょうか。 本当にメモリが足りなければOutOfMemoryExceptionが発生しますよ(手動にしろ自動にしろ)。 メモリ不足に対して、GC.Collectを呼び出したからといって何の解決にもなりません。 [ メッセージ編集済み 編集者: Tdnr_Sym 編集日時 2009-02-15 13:50 ] | ||||||||||||||||
|
投稿日時: 2009-02-17 22:01
補足ありがとうございます。 CLR は常にフル GC を行うわけではありませんが、常に手動でフル GC が行われているわけですから、CLR による自動回収はされないのではないか?と、思っているわけです。Part I<microsoft.com> に、「ガベージコレクションは、ジェネレーション0がいっぱいになったときに発生する」と書かれています。ここで、前提として、 * 頻繁に GC.Collect() が呼び出される。 とします。このとき、 1.頻繁に全ジェネレーションが回収されているので、ジェネレーション0がいっぱいにならず、自動回収は行われない。 2.自動回収が行われないので、「本来なら解放されやすいオブジェクトが解放されにくくな(る)」ということもない。 と思うのです。 確かに、手動による GC.Collect で、参照されているオブジェクトのジェネレーションが上がり、CLR による要求からは回収されにくくなるでしょう。しかし、次にも手動によって全ジェネレーションに対する回収要求がくるので、ジェネレーションを上げた意味がなくなると思うのです。 ※余談 ん?連続してメモリを確保する場合、例えば100回ループの50回目でジェネレーション0がいっぱいになったとすると、50回目より前に確保したエリアはジェネレーションが上がる?ライフ サイクルは、50回目以降と同じだとコード化されていても? | ||||||||||||||||
|
投稿日時: 2009-02-18 03:37
こんばんは。
なるほどです。 確かに常にフルGCしていれば、ジェネレーションなんて関係なさそうですね。
はい。上がりますね。 このスレ↓の現象を検証するため、プロファイラ等を使って確かめましたが、 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=47943&forum=7&start=24 ループ中に動的に作成したLabelオブジェクトが、gen0〜gen1,2 にまで分布しておりました。 作成した動的Labelは短命なため、gen2までたどり着く割合はほんの僅かでしたが。 |
1