はじめまして、よく過去ログを参考にさせていただいています。
VC++6.0 MFC
Win2000
まだまだペーペーなので間違っているかも知れませんが、
・リストボックス表示限界はメモリの許容する範囲
ですよね?
現在開発しているモノは実行状況及び、実行結果ログ
をリストボックスにて適時出力しています。
問題になっているのは表示が10000件を超えたあたりから
表示が壊れる(他のウィンドウにも影響有り)のです。
例: まったく関係の無い個所にスクロールバーがいきなり表示される。
その後異常終了する。
試しに1000毎にResetContentを発行してみたのですが、
結果は同一で、やはりウインドウが壊れるのです。
そして、メモリまでは開放されているように見えませんでした。
(タスクマネージャ上で確認)
リストボックスの内部ではどのようにメモリ管理を
行っているのでしょうか?
また、どのようにしてリストボックスが確保した領域を
開放するのでしょうか?
もしかして、表示件数が不定でかつ、大量の場合はリストボックスを
使用するべきではないのでしょうか?
ごめんなさい、内部の管理方法までは知らないのですが、
単純に思ったことがありまして。
このリストボックス、どんな用途なんですかね。
リストの中からユーザがひとつ選ぶためのものだとしたら、
数千件?数万件?の候補の中から選ばせるというのは・・・(汗
あまり使い手にとって優しいアプリとは言えませんよね。
何か条件をもって、候補を絞り込ませる仕様を入れれば、
最大件数問題も回避できるような気がしまして。
レスありがとうございます。
確かに数万件の候補の中から選ばせるというのは
リストボックスの本来の用途とは外れていますね。
今回の満たしたい用途としては
・ログ、作業状況のリアルタイム表示
・水平、垂直スクロールバーの実装
なのです。
リスト内より選択する機能は必要ありません。
単純に表示がしたかったのです。
今回、リストボックスを使った意図は恥ずかしながらありません(汗
ですが、他のコントロールでも同じような問題が発生しそうな
気がしています。(n件のデータを表示するための領域の確保、開放)
最大件数の問題は「ある程度の目安を設けて表示を初期化」
で解決するのですが、ResetContentではメモリは開放しないようでした。
VBでのリストボックスで同じような処理をした場合、開放しているので
必ずメモリ開放のインタフェースはあると思うのですが...
リストボックスは Windows 3.1 時代から存在するコントロールなので、無茶な利用には
耐えません。
メモリ管理も内部に完全に隠蔽されているので、外部から救援の手を差し伸べることも
ままなりません。限界を超えるといきなり破綻してしまいます。
リストビューコントロールなら「仮想リスト」という技術を使うことで、アイテムが数
万件あっても、アプリケーション側の実装次第で破綻することなく表示が可能です。
(使いやすいかどうかは別として)
「仮想リスト」については、MSDN Library で解説されているので、まずはそれを参照し
てみてください。
普通にResetContentすればリストボックスが使っているメモリは
解放されると思いますけど。
なにか付随するデータのメモリの解放漏れということはないでしょうか。
たとえば、リストボックスに10000件追加するだけのプログラム、
リストボックスに追加する処理を省略したプログラム、
などと比較してみてはどうでしょう。
渡している文字列に、本来、そのコード体系にはないコードが
まざりこんでいる可能性はないですか?
NT系であれば、内部でUnicodeに変換して格納してと
ややこしそうなことをやっているはずですから
本来あってはいけないコードがまざっていると
メモリ管理が破綻する可能性が、、、すこしはあるかもしれません
ちなみに
>・リストボックス表示限界はメモリの許容する範囲
リソースの許容する範囲、だと思います
渋木宏明(ひどり)さん、dairygoods さん、たみあ さん
レスありがとうございます。
1、単純に60000件追加するサンプルプログラムを作製し、
ResetContentを発行するとメモリが開放された。
2、出力するべきログ、実行状況メッセージは他APP(自前)にて
発行しているので不正コードは無いモノと思われる。
3、現在の作りから大幅な変更は手がかかるのでリストコントロール
にて作製する。(空きができましたらぜひリストビューコントロール
にて作製してみます。)
以上より、取りあえず「メモリの開放漏れ」から疑ってみます。
解決しましたーーーーー(^○^)
原因はリストボックスの水平スクロールの対応のため以下ソースを
リストボックスに値を追加毎に処理していました。
開放漏れと言うよりは…なんでしょう…
~略~
/**************************************/
/* 水平スクロール対応 */
/**************************************/
pDc = pVShowList->GetDC(); /* リストボックスのデバイスコンテキストを取得 */
pOldFont = pDc->SelectObject(pVShowList->GetFont());
/* デバイスコンテキストにリストボックスのフォントを指定 */
nSize = pDc->GetTextExtent(出力されるメッセージ).cx;
/* 格納データ雛形の文字列幅取得 */
/* 文字幅最大超判別 */
if(lngVListBoxMaxLine < nSize){ /* 大きい場合 */
lngVListBoxMaxLine = nSize; /* 外部変数に設定 */
pVShowList->SetHorizontalExtent(lngVListBoxMaxLine + 5);
/* 水平スクロール振幅を設定 */
}
~略~
この処理を想定される最大メッセージ長で設定するように変更しOnInintDailogに移動し
追加毎からコメントアウトしました。
直接の原因がGetDC、SelectObject、SetHorizontalExtentのどれなのかは
これから解析します。
取り急ぎ解決報告です。
皆さんありがとうございました。
解析てか、それしかコードが書いてないなら、ものの見事にリソースリークしてます
よ。
pDc = pVShowList->GetDC();
したら
pVShowList->ReleaseDC(pDC);
で後始末しなくちゃならないし、その間にある
pOldFont = pDc->SelectObject(pVShowList->GetFont());
だって、
pDC->SelectObject (pOldFont);
しなくちゃ駄目です。