メモリリーク GDI関連のチェック方法
☆メモリリーク GDI関連のチェック方法
別にCとは限らないんですが、
デバイスコンテキストを使うアプリを作っていて、いつものメモリリーク(解放忘れなど)
とは違うリーク忘れがあって、見つけるのに苦労したので覚書しておきます。
まずそれを発見する方法ですが、通常のメモリークなら、
タスクマネージャーのメモリの残量をアプリを操作しながら見て入れば大体わかるのですが、
デバイスコンテキスト周りの場合、GDIオブジェクトというのをみないといけないようで、
Winodws8のタスクマネージャーではどこにもなさそうです。
WinodwsXPにはあった。
そこで、フリーソフトの「ProcessExplorer」というので
(初期状態ではGDIオブジェクトはないので)、「View」メニュー→「Select Columns」→「Process Memory」タブで
GDIオブジェクトを表示させます。
アプリをデバッグなどで動かしたら、EXE名が現れるので、そこのGDIオブジェクトを見ながら操作します。
(通常のメモリリークもタスクマネージャーでみたりします。)
リークしている場合、
ここで公開したような小さいアプリならわかりにくいかも知れませんし、
複雑な事はしないので、アプリを閉じてしまえば最悪は良いんですけど、
色々する複雑な事をする比較的大きいアプリだと
(それが意図した確保とかなら良いのですが)
値が増えて、リークの場合はするごとに
そのリークした増えた分の値は戻る事はないので
スペックの良くないパソコンだと固まります。
で、保存機能があるなら保存していないと、それまでの作業が全部パァーになってしまったりします。
アプリの推奨スペックより遅いものならハード的に無理なところもあって、
そこでリークなしで作っていて動かないのは当然ですが、
推奨スペックを満たしたパソコンなら、トロトロしながらも
動いていかないと駄目となるでしょう。
リークはできるだけなくさないと駄目になります。
以下に一応、失敗例も書いておきます。
直してしまって、いまいちどこだか覚えていませんが、多分この辺だったというのを書いておきます。
過去のソースも残っていますが、どこだか忘れぎみ。
デバイスコンテキストとは関係ないですが、わかりにくかったのを覚書しておきます。
処理の一部部分をサンプルから頂いて来て、
クラスで、NewしたのをDeleteしていなかった。
それに気が付くまで、ファイルを掴んだままで、リーク。
ここも気が付かず直すのに苦労しました。
短縮で書くプログラムは気づきにくいので、
多少文字列が長くなろうが、できるだけちゃんと書いた方が良いのかも知れません。
多分、この辺でミスっていたんだったと思います。
わかれば簡単な事ですが、見つけるまで時間が掛ったりします。
適当にプログラムしてしまうと、リーク対応が一番めんどくさいのですが、
ああでもないこうでもない、ここと仮定して深く見るとかなど、
知恵熱出すぐらい脳を使う事もあり、これはこれで面白く感じてしまいます。
対処出来てスムーズに動いた時の満足感がまた良いです。
初めからキッチリ書けば良いんですが。
仕事とかなら自分で一から書けずに、改修とかもありますから、
こういうのも気にしていると良いかも知れません。
ボケ防止に自分専用のアプリをプログラミングするのも良いかも知れません。
記述:2014年09月頃
別にCとは限らないんですが、
デバイスコンテキストを使うアプリを作っていて、いつものメモリリーク(解放忘れなど)
とは違うリーク忘れがあって、見つけるのに苦労したので覚書しておきます。
まずそれを発見する方法ですが、通常のメモリークなら、
タスクマネージャーのメモリの残量をアプリを操作しながら見て入れば大体わかるのですが、
デバイスコンテキスト周りの場合、GDIオブジェクトというのをみないといけないようで、
Winodws8のタスクマネージャーではどこにもなさそうです。
WinodwsXPにはあった。
そこで、フリーソフトの「ProcessExplorer」というので
(初期状態ではGDIオブジェクトはないので)、「View」メニュー→「Select Columns」→「Process Memory」タブで
GDIオブジェクトを表示させます。
アプリをデバッグなどで動かしたら、EXE名が現れるので、そこのGDIオブジェクトを見ながら操作します。
(通常のメモリリークもタスクマネージャーでみたりします。)
リークしている場合、
ここで公開したような小さいアプリならわかりにくいかも知れませんし、
複雑な事はしないので、アプリを閉じてしまえば最悪は良いんですけど、
色々する複雑な事をする比較的大きいアプリだと
(それが意図した確保とかなら良いのですが)
値が増えて、リークの場合はするごとに
そのリークした増えた分の値は戻る事はないので
スペックの良くないパソコンだと固まります。
で、保存機能があるなら保存していないと、それまでの作業が全部パァーになってしまったりします。
アプリの推奨スペックより遅いものならハード的に無理なところもあって、
そこでリークなしで作っていて動かないのは当然ですが、
推奨スペックを満たしたパソコンなら、トロトロしながらも
動いていかないと駄目となるでしょう。
リークはできるだけなくさないと駄目になります。
以下に一応、失敗例も書いておきます。
・その失敗の例
直してしまって、いまいちどこだか覚えていませんが、多分この辺だったというのを書いておきます。
過去のソースも残っていますが、どこだか忘れぎみ。
①WM_PAINT辺り等の描画系で、
SelectObject(hmemdc , CreateSolidBrush(RGB(0xFF , 0xFF , 0xFF)));  
こんな事をしていた。
で、hmemdcの解放はアプリ終了時とかにしていた。
裏デバイスコンテキスト(この場合、hmemdc)として使っていたんですが、
この裏デバイスコンテキストが解放されないと、
CreateSolidBrushは解放されないので、WM_PAINT毎にどんどん増えていく。
なので、アプリ開始時にCreateSolidBrushを1回だけする事で解決。
どこかで1回だけ、HBRUSH hbrush;とかにCreateSolidBrushをして
SelectObject(hmemdc , hbrush);
とかにする。
②これもWM_PAINT辺り等の描画系で、
hPen = CreatePen(PS_DOT, 1, RGB(100, 100, 100));
hOldPen = SelectObject(hmemdc, hPen);
なんか処理
DeleteObject(hPen);
こんな感じ。
これも裏デバイスコンテキスト(この場合、hmemdc)として使っていたんですが、
DeleteObjectしているのに、この裏デバイスコンテキストが解放されないと、
hPenは解放されないので、WM_PAINT毎にどんどん増えていく。
なので、アプリ開始時にCreatePenを1回だけする事で解決。
どこかで1回だけ、HPEN hPen;とかにCreatePenをして
SelectObject(hmemdc, hPen);
とかにする。
③もういらない作業用のデバイスコンテキストの解放忘れ。
・その他の失敗
デバイスコンテキストとは関係ないですが、わかりにくかったのを覚書しておきます。
処理の一部部分をサンプルから頂いて来て、
クラスで、NewしたのをDeleteしていなかった。
それに気が付くまで、ファイルを掴んだままで、リーク。
GDI+で、
Gdiplus::Bitmap* pImage;
Bitmap pImage(wszFileName);
とか書かれていたので、見逃してしまい。
省略せずちゃんと書いて、
Gdiplus::Bitmap* pImage;
Bitmap* pImage = new Bitmap(wszFileName);
などにしてちゃんとdelete(pImage);
ここも気が付かず直すのに苦労しました。
短縮で書くプログラムは気づきにくいので、
多少文字列が長くなろうが、できるだけちゃんと書いた方が良いのかも知れません。
・感想など
多分、この辺でミスっていたんだったと思います。
わかれば簡単な事ですが、見つけるまで時間が掛ったりします。
適当にプログラムしてしまうと、リーク対応が一番めんどくさいのですが、
ああでもないこうでもない、ここと仮定して深く見るとかなど、
知恵熱出すぐらい脳を使う事もあり、これはこれで面白く感じてしまいます。
対処出来てスムーズに動いた時の満足感がまた良いです。
初めからキッチリ書けば良いんですが。
仕事とかなら自分で一から書けずに、改修とかもありますから、
こういうのも気にしていると良いかも知れません。
ボケ防止に自分専用のアプリをプログラミングするのも良いかも知れません。
記述:2014年09月頃
Twitter Facebook Google+ はてな Pocket LINE
管理人による書き込みの確認後、荒らし書き込みでない場合に表示させていただきます。
悪意ある書き込みや挑発的な書き込みと思われる内容は、表示させません。
その為、ちょっと書き込みから表示までに時間がかかってしまいます。ご了承下さい。
暑さの一番の原因はなんだと思いますか?
あなたの支持する政党はどの党ですか?
今のページの関連ページのリストへ
ザ・覚書のトップページに戻る
全ページのリストへ