トップ回答者
Bitmapoオブジェクトを作成しDispose下にも関わらずメモリリークが発生する

質問
-
お世話になっております。
C#でプログラムを作成しているのですが、Bitmapオブジェクトを作成しDisposeしたにも関わらず、メモリがリークする現象が発生しました。
Disposeの処理は行われているのでリソース(GDI)は解放されているのですが、なぜかメモリ(ワーキングセット/プライベートワーキングセット)は減りません。
現象は発生する端末と発生しない端末があり、共通しているのは.NetのVerが4.5ということだけです。
CGを強制的に動かしてもメモリは減りませんでした。
また、.Net4.5をアンインストールし.Net4.0、.Net3.5のいずれかにするとリークはおきませんでした。①Bitmapのメモリ解放処理でDispose以外に何か必要なのでしょうか。
調べた限り、Disposeする/オブジェクトにnullを設定する、という2つが一般的なようで、両方入れていますが効果なしでした。
②同じような現象を経験された方がいらっしゃいましたら、その時の原因など、情報をお持ちでしたらご教示ください。
③.Net4.0→4.5の仕様変更でBitmap解放処理が変更されたなど情報をお持ちの方がいらっしゃいましたらご教示ください。
自分で調べた限り解放処理の仕様が変わった、という情報は見つけられませんでした。
よろしくお願いいたします。
回答
すべての返信
-
Disposeの処理は行われているのでリソース(GDI)は解放されているのですが、なぜかメモリ(ワーキングセット/プライベートワーキングセット)は減りません。
どこまで確認されたのでしょうか? 「メモリは減りません」はリソースモニター等で確認した事実と思われますが、「リソースは解放されている」は何をもって確認されたのでしょうか? 単にDisposeを呼び出したことによる希望的観測でしょうか?
主観に基づくあいまいな判断をするのではなく、プロファイラーを使用して定量的に確認してください。.NETのプロファイラーであれば各型ごとに何個のオブジェクトが生存しているのか確認できます。プログラムの動作と比較して意図せず解放されずに残っているオブジェクト・型が何であるかを特定してください。そもそもBitmapクラスではない可能性もあります。
また.NETオブジェクトについてはリークしていない可能性もあります。その場合はネイティブリソースのリークですので、パフォーマンスカウンター等の別の方法でリーク対象を特定することになります。
-
基本的に Bitmap クラスは GDI+ のかんたんなラッパーに過ぎませんので、.NET Framework のバージョンによらないはずです。
念のために確認して欲しいのですが、Bitmap の生成と破棄(Dispose)だけのシンプルなプロジェクトでも再現しますか?Azulean様
お返事遅くなりました。
シンプルなプログラムで確認もとりました。こちらでは再現しておりません。
ただ、現在作成しているプログラムを1行ずつ確認したところ、Bitmapをnewしたらメモリが増加するというのは間違いありませんでした。
原因追究手段も手詰まり状態になったので、まず基本が抜けている可能性があるのでは…?というところと
似たようなことを経験された方がいないか。とわらをもすがる思いで投稿させていただいた次第です。
-
佐祐理様
ご連絡おそくなりました。
>「リソースは解放されている」
こちらはタスクマネージャーのGDIの表示を(デバッグで追いながら)Dispose前後で確認しました。あとはフリーのツールでGDIを計測するツールがあったのでこちらも使用したりしました。フリーのツールでBitmapのオブジェクトが減っていたので、解放されていると判断しました。
>また.NETオブジェクトについてはリークしていない可能性もあります。その場合はネイティブリソースのリークですので、パフォーマンスカウンター等の別の方法でリーク対象を特定することになります。
そうなると、Disposeでは解決しない別の問題があるかもしれないということでしょうか…原因の特定方法が難しそうです…。
こうなるとパフォーマンスモニタなので、あたりを付けて計測していくほか手段はないでしょうか。よろしくお願いいたします。
-
佐祐理様
ご連絡おそくなりました。
ご回答ありがとうございます。
再掲していただいた件ですが、こちらは確認しております。(前回フリーのソフトを使用して…というのはこのことでした)
その結果、Bitmap型のオブジェクトの個数がNewする前とDispose後で同じであること、ほかの型のオブジェクトの個数が増えていないことを確認しました。
なので、オブジェクト自体の個数は減っている(解放されている)と結論付けました。
とりあえずですが、シンプルな再現プログラムがまだできていないので、まずはこちらから手を付けてみることにしました。
進展がありましたら再度コメントさせていただきたいと思います。
-
-
GCの動作やタイミング、OSからのメモリ確保の挙動などは、CLRの深い部分の動作であり、CLRのバージョンが変わると結構挙動も変わる場合があります。
また、.NETやGCでリリースされるメモリはマネージメモリですが、これはOSから確保した仮想メモリ空間の一部が割り当てられているのであり、OSからのメモリ確保と同一タイミングではありません。
※まずOSからまとめてメモリ領域を確保し、マネージの世界ではGCで細々と管理する
また、ワーキングセットは上記OSから確保したメモリのうち物理メモリに割り当てられている量で、これもプロセスのメモリアクセス状況に基づいてOSが自動で制御するものですから、CLRのバージョンによってメモリアクセスの挙動に変化があれば、ワーキングセットのサイズにも影響があります。
※「ワーキングセットが減らない=リーク」ということではない