2010/03/11

Windows XPでのC#の動作の重さを解消する方法

C#で組んだアプリがどうもなーんかモッサリ動作に感じる原因が
やーっと分かりました。

● フォームを最小化した後、復帰するときにすごく重いことがある。

最小化したフォームを復帰させるとき非常に重たいことがある。
PCがフリーズした状態で徐々にゆっくりフォームが表示されていく
感じ。時々起こるこれが実際以上に体感速度をすごく遅くしてる。

● 原因はフォーム最小化時のスワップアウト

http://d.hatena.ne.jp/NyaRuRu/20051022

Windows XPはフォームを最小化するとプロセスの"working set"を
縮小する。タスクマネージャのプロセスのメモリ使用量をみてると、
フォームを最小化したときに使用量がぐっと減るのが分かる。

http://d.hatena.ne.jp/NyaRuRu/20071010/p1
http://d.hatena.ne.jp/NyaRuRu/20071027/p1

この状態で他のプロセスがメモリを消費すると、簡単にスワップアウトしてしまう。
で、さらにスワップ状態でGCが動いたりすると、とても重たい処理に発展しちゃったり
することがあるらしい。
.netのメモリ消費量の多さとこのへんの動作の重さがが重なって結果的に
とっても重くなってる感じがする。

● で、どうやって回避するか

Firefoxとかのメモリを食うアプリは最小化時のスワップアウトを回避してるらしい。
これ、

http://support.microsoft.com/kb/293215/en-us

によると、WM_SYSCOMMANDメッセージのSC_MINIMIZEコマンド
の処理中にWorking Setの圧縮が行われているそうなので、
ここをinterceptすることでスワップアウトを阻止できるそうだ。
ただ、メッセージハンドラを直接触れない(多分)C#ではこのままの方法は
とれない。

● タスクトレイを使う方法

常駐型のソフトに関してはタスクトレイに常駐させてしまう方法をとることができる。
まずはNotifyIconを使ってタスクトレイにアイコンを配置して、
フォームの方の最小化ボタンはMinimizeBoxプロパティで禁止してしまう。
で、FormClosingイベントでフォームのVisibleをFlaseにするようにする。
VisibleをFalseにした際には問題のスワップアウトは発生しないようで、
これで動作は非常に快適になった。

●で、普通に最小化したいときはどうするのか

最小化ボタンを押したときに最小化前に発生するイベントが無いのが問題。
CloseしたときのFormClosingに相当するものがあればいいんだけど。
Layoutイベントで
this.WindowState==FormWindowState.Minimized
となるときを拾えば最小化前に処理を発生させることはできそうなんだけど、
FormClosingでのe.Cancelに相当するものが無い。
すなわち、最小化前にVisibleをfalseにすることはできても、
その後で発生するMinimizeを止めることができない。

さて、どうしたものか・・・。

1 件のコメント:

Tnk さんのコメント...

C#でもウィンドウメッセージハンドラのオーバライドが出来るみたい。試してみよっと。