- PR -

GC.WaitForPendingFinalizersについて

1
投稿者投稿内容
未記入
常連さん
会議室デビュー日: 2004/08/26
投稿数: 34
投稿日時: 2009-02-13 09:59
ASP.NET 2003で、webアプリを開発しています。
負荷試験にて、トップページに毎秒1件のアクセスを実施したところ、
メモリの使用量が右上がりに増えていきました。
トップページのロード処理の最後に
GC.Collect()
GC.WaitForPendingFinalizers()
を追記したところ、
メモリの使用量は安定しましたが、
GC.WaitForPendingFinalizers()
の処理で、時間が掛かってしまうようになりました。

GC.WaitForPendingFinalizers()
はGC.Collect()が完了するまで待機する、という認識で
正しいでしょうか?
GC.WaitForPendingFinalizers()
を記述しなかった場合、GC.Collect()は効果があるのでしょうか?

以上です。ご教授の程、よろしくお願い致します。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2009-02-13 11:15
> GC.WaitForPendingFinalizers()
> はGC.Collect()が完了するまで待機する、という認識で
> 正しいでしょうか?

GC が回収したオブジェクトの内、ファイナライザを実行する必要のあるオブジェクトは、F リーチャブルキューという特別な領域に置かれます。そして、専用のスレッドでファイナライザが順番に実行されます。
WaitForPendingFinalizers メソッドは、この F リーチャブルキューが空になるまで待機するためのメソッドです。


> GC.WaitForPendingFinalizers()
> を記述しなかった場合、GC.Collect()は効果があるのでしょうか?

WaitForPendingFinalizers を呼び出すかどうかに関わらず、回収自体は行われます。
メモリの使用量や処理時間については、
WaitForPendingFinalizers を呼び出す場合と呼び出さない場合で実際に比較してみれば良いです。

ただ、「メモリの使用量が右上がりに増えた」とのことですが、それで実際にメモリ不足やら断片化の問題が発生していないのなら、
GC.Collect を行う必要はないのではないでしょうか。
GC は必要に応じて勝手に回収してくれます。下手に強制実行するとパフォーマンスが落ちる可能性があります。

_________________
C#と諸々
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2009-02-13 11:40
それなりにちゃんと設計して作ってれば、メモリ使用量は上限があるはずです。
GCは必要がなければ実行されません。なので、右肩上がりになっててもそれは解放する必要がないからでしょう。
逆に、無計画に GC.Collect してしまうと、不必要なジェネレーション昇格が発生し、本来なら解放されやすいオブジェクトが解放されにくくなります。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2009-02-14 14:55
引用:

囚人さんの書き込み (2009-02-13 11:40) より:
無計画に GC.Collect してしまうと、不必要なジェネレーション昇格が発生し、本来なら解放されやすいオブジェクトが解放されにくくなります。


私もそう思っているのですが、ジェネレーション指定のない GC.Collect は、全てのジェネレーションを回収しますよね。ということは、「本来なら解放されやすいオブジェクトが解放されにくくな(る)」ということは、ないのでは?
(今回の件では Page.Load イベントに GC.Collect を書いているため、自動回収が必要ないくらい頻繁に手動回収が実行されるという前提です。)
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2009-02-15 13:37
こんにちは。

引用:

Jittaさんの書き込み (2009-02-14 14:55) より:
私もそう思っているのですが、ジェネレーション指定のない GC.Collect は、全てのジェネレーションを回収しますよね。



すこし補足させていただくと
「ジェネレーション指定のない GC.Collect は、全てのジェネレーションのオブジェクトを対象に使用されていないかチェックし、もし使われていなければそのメモリを回収します」
でしょうか。

引用:

(今回の件では Page.Load イベントに 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 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2009-02-17 22:01
引用:

Tdnr_Symさんの書き込み (2009-02-15 13:37) より:
CLRの自動回収は常にフルGCを行うわけではありませんよね。


 補足ありがとうございます。

 CLR は常にフル GC を行うわけではありませんが、常に手動でフル GC が行われているわけですから、CLR による自動回収はされないのではないか?と、思っているわけです。Part I<microsoft.com> に、「ガベージコレクションは、ジェネレーション0がいっぱいになったときに発生する」と書かれています。ここで、前提として、

* 頻繁に GC.Collect() が呼び出される。

とします。このとき、

1.頻繁に全ジェネレーションが回収されているので、ジェネレーション0がいっぱいにならず、自動回収は行われない。
2.自動回収が行われないので、「本来なら解放されやすいオブジェクトが解放されにくくな(る)」ということもない。

と思うのです。

 確かに、手動による GC.Collect で、参照されているオブジェクトのジェネレーションが上がり、CLR による要求からは回収されにくくなるでしょう。しかし、次にも手動によって全ジェネレーションに対する回収要求がくるので、ジェネレーションを上げた意味がなくなると思うのです。

※余談
 ん?連続してメモリを確保する場合、例えば100回ループの50回目でジェネレーション0がいっぱいになったとすると、50回目より前に確保したエリアはジェネレーションが上がる?ライフ サイクルは、50回目以降と同じだとコード化されていても?
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2009-02-18 03:37
こんばんは。

引用:

Jittaさんの書き込み (2009-02-17 22:01) より:
2.自動回収が行われないので、「本来なら解放されやすいオブジェクトが解放されにくくな(る)」ということもない。
と思うのです。
 確かに、手動による GC.Collect で、参照されているオブジェクトのジェネレーションが上がり、CLR による要求からは回収されにくくなるでしょう。しかし、次にも手動によって全ジェネレーションに対する回収要求がくるので、ジェネレーションを上げた意味がなくなると思うのです。



なるほどです。
確かに常にフルGCしていれば、ジェネレーションなんて関係なさそうですね。


引用:

 ん?連続してメモリを確保する場合、例えば100回ループの50回目でジェネレーション0がいっぱいになったとすると、50回目より前に確保したエリアはジェネレーションが上がる?ライフ サイクルは、50回目以降と同じだとコード化されていても?



はい。上がりますね。
このスレ↓の現象を検証するため、プロファイラ等を使って確かめましたが、
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=47943&forum=7&start=24

ループ中に動的に作成したLabelオブジェクトが、gen0〜gen1,2 にまで分布しておりました。
作成した動的Labelは短命なため、gen2までたどり着く割合はほんの僅かでしたが。

1

スキルアップ/キャリアアップ(JOB@IT)