Delphiで作ったアプリケーションの試験をしているのですが
メモリリークは無いのにOSのメモリが消費されていきます。
常駐ソフトは全て外してウイルスチェックスパイウエアチェック済みです。
メモリリークが無いという根拠はMemcheckの他、タスクマネージャーで
プロセスを見るとDelphiアプリが使用しているメモリが増えていないからです。
ですが、コミットチャージの欄のメモリは増えていき半日で50Mほど増えます。
消費されたメモリはDelphiアプリを終了しても解放せず、再起動まで残ります。もちろんこのアプリを起動しなければ発生しない現象です。
1クラス毎に色々調べてはいるのですがDelphiアプリのメモリ消費量の
表示には問題がないせいもあり原因がつかめません。
そもそもDelphiが使用していないのにメモリが減るようなことがあるので
しょうか?
例えば共有メモリのようにシステムワイドなリソースを消費している場合は
ありえるんじゃないでしょうか。
レスありがとうございます。
基本的なDelphiアプリの内容としては、ログを取っていくだけのもので
共有メモリは使っていません。
試しにメモリクリーナーを使ってみましたが変化無しでした。
ファイルかなにかのキャッシュに使われているのかと思いましたが
どんなに空きメモリが減っても開放することは無くOSからメモリ不足の
警告が出ます。
他のアプリでも同じように消費されていくのではないでしょうか。
Delphiとは無関係のような気がしますが。
たとえばExcelを起動して、終わっても元の空きメモリ容量にならない。
たしかにIEとかを起動し終了しても空きメモリの量が戻らない現象は
あります。
IEとかでは10M消費していたとしたら、終了させると8Mぐらいは
返ってくるのですが、
今回作成したDelphiアプリを起動すると実行ファイルが6M。
データ保存用クラスの生成で10Mの計16Mになったとすると
終了させても6Mしか開放されず、まるでメモリリークのようになって
いるのです。
何度実行、終了してもメモリの消費ばかりが続き、OSを再起動しないと
開放されません。
テストで、データ保存用クラスを生成しなければ、6Mだけで問題にならないのでしょうか?少しずつ外したりしてテストするしか無いのかな?
編集 削除保存クラスに問題があると思うので、半分ぐらいの処理をコメント化した
のですが、やはり発生しました。
HOtaさんがおっしゃるとおり思い切って全部コメントにして少しずつ
テストしたいと思います。
起動してから現象を確認するまで20〜30分かかるため、もう少し
現象を出やすくするテストもしてみます。
私は仕事、趣味でDelphiを使用していますが、このような現象は一度もありません。
プログラミング上の問題のような気がします。どこかに悪い部分が存在するのでしょうね。
具体的な処理内容やコードがわからないと答えられないかもしれませんね。
以下を参照下さい。
http://leed.issp.u-tokyo.ac.jp/~takeuchi/delphi/article/080/080495.html
で、ここのFastMMを入れると解決するかもです。
http://sourceforge.net/projects/fastmm/
>以下を参照下さい。
>http://leed.issp.u-tokyo.ac.jp/~takeuchi/delphi/article/080/080495.html
この現象の場合、アプリを終了したらメモリは回復すると思うのですが・・・。
色々レスありがとうございます。
問題部分をコメントにするほか各環境にて確認したところなんと非力な環境でのみ発生するようです。
もしかすると
http://ahfb1.kek.jp/~tobiyama/epics/epics-pc/troubles.html#Q2
の現象かもしれません。
データ保存処理に時間がかかりすぎて、この処理中に再実行され解放されないまま終了していくのかもしれません。
まだ推測ですので証明まで少々お待ちください。
例)
procedure THogeForm.Button1Click(Sender: TObject);
var
button:TButton;
begin
button:=TButton.Create(Self);
button.Parent := Self;
〜〜
//最後のbutton.Free; を忘れる
end;
ボタンを押す毎に、新しいボタンインスタンスを作成するが、破棄しないためメモリ・リソースを食いつぶす。
ただし、ボタンの所有者がフォームのため、フォームの破棄時に、
一緒に破棄されるため、メモリーリークとして報告されない。
このように、誰かが代わりにお掃除してくれる場合、見落としてしまう場合があります。
原因となる箇所が突きとめられました。
しかし、環境により発生したりしなかったりとまだまだ謎です。
ソースを示しますが問題部分を大げさに抽出しただけで
さらにこれを実行しても現象は発生しませんでした。
下記のようなコードでSaveToFileを呼ぶと現象が発生しメモリが
減っていくようです。
※Delphiアプリの消費メモリは変動なし、終了してもメモリは回復しない
【概要】
いくつかのTStringListをTListによって管理させます。
ただし生成時、独自拡張したTStringListExを生成させ開放はTStringListとして
実行します。(プログラムミスを再現)
値を入れておいたTStringListExから取り出した値はまとめてファイル化します。
【現象発生の可否】
非力なWindows2000SP3環境で発生。
TPerson.SaveToFileメソッド中のSaveToFileをコメント化すると改善
プログラムミスである
TStringList(t[j]).Free;
を
TStringListEx(t[j]).Free;
にすると改善
以下がソースです。
※TPersonの生成やフォームの定義は省略
// TStringListの拡張クラス
type
TStringListEx = class(TStringList)
private
{ Private 宣言 }
FP : Pointer;
public
{ Public 宣言 }
constructor Create();
destructor Destroy();override;
end;
type
TPerson = class(TPersistent)
private
{ Private 宣言 }
public
{ Public 宣言 }
function SaveToFile(const FileName : string) : Boolean;
end;
{ TStringListEx }
constructor TStringListEx.Create();
begin
// 状態を明確にするためメモリを大量確保
FP := AllocMem(1000000);
end;
destructor TStringListEx.Destroy;
begin
FreeMem(FP);
inherited;
end;
{ TPerson }
function TPerson.SaveToFile(const FileName: string): Boolean;
var
t : TList;
ts,tt : TStringList;
i,j : Integer;
begin
t := TList.Create;
tt := TStringList.Create;
try
// TStringListExを生成しリストに追加
for j := 0 to 25 do begin
ts := TStringListEx.Create;
ts.Add(StringOfChar(Char($41 + j),100));
t.Add(ts);
end;
// リストから保存用のTStringListを作成し保存
for j := 0 to t.Count-1 do begin
ts := TStringList(t[j]);
tt.Add(ts.Text);
end;
tt.SaveToFile(FileName);
// 不要なクラスを破棄
for j := 0 to t.Count-1 do begin
TStringList(t[j]).Free; // ←問題点
end;
t.Clear;
finally
tt.Free;
t.Free;
end;
end;
> TStringList(t[j]).Free; // ←問題点
↓
ts := TStringList(t[j]);
ts.Free;
かなぁ・・・
> ts,tt : TStringList;
これも、TStringsで宣言するかも・・・気分で
または、D5以降であれば、TListではなく、contnrsをuses して、TObjectListを使って、Clearするだけにする。
デストラクタは
destructor Destroy();override;
のように仮想なので
TStringList(t[j]).Free;
は問題ないと思うのですが・・・
TStringList(t[j]).Free;
これで、TStringListEx.Destroy; は実行されるし、
ttp://www.yks.ne.jp/~hori/MemCheck.html によりメモリーリークチェックしても報告されない。
では・・・これが当たりか?
ttp://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=080495
色々ご教授ありがとうございます
サンプルで言うところのTStringListEx.Destroyメソッドが
ちゃんと実行されメモリリークなど発生しない事は
わかるのですが、現象がこれで改善されてしまいます。
いくつかの環境で試しているのですが
A:Celeron400MHz MEM:128M OS:Win2000(Pro)SP4 状態:×
B:Celeron400MHz MEM:128M OS:Win2000(Server)SP4 状態:○
C:PentiumM1.5M MEM:768M OS:WinXP(HOME)SP1 状態:○
状態が×の環境が他に2例ほどあるのですがAの環境に酷似している
こと以外は不明です。
状態が×のものではタスクマネージャーのプロセス一覧とパフォーマンスの
メモリ表示で確認すると
プロセス一覧のメモリには変化が無く、パフォーマンスのメモリが減り
最後にはOSが不安定になります。
見えないプロセスがあるようなイメージなので、色々調べているのですが
まだ解決には至りません。
開発環境をDelphi5SP1からDelphi6にして変化があるか試す事にします。
書き込み中に返信があったようで再度書き込みます。
orzさんのリンク先にあった「FastMM」または同等品を導入して
変化があるか試したいと思います。
FastMMを使ったところ状況が改善されました。
年の瀬で時間がなかったので、FastMMを含めたいくつかを
同時に改善したため断定ではありませんが
原因の1つになっていると思われます。
この後、改善した箇所を1つずつ元に戻しながら試験を行いますが
時間がかかるため一旦解決と致します。
ありがとうございました。
>FastMMを使ったところ状況が改善されました。
ここの上から9つ目のレスで書いていたのですけどねぇ・・・
気づかなかったのかな?(>_<;)
> >FastMMを使ったところ状況が改善されました。
> ここの上から9つ目のレスで書いていたのですけどねぇ・・・
あ〜、ほんとだねぇ。
しかも、MLの同じ記事指しているし、具体的にFastMMの名前まで出しておられる。
あたくしのレスより詳しいではありませんか(^^ゞ
次の、これでスルーしちゃったとか
> この現象の場合、アプリを終了したらメモリは回復すると思うのですが・・・。
コレに懲りずにがんばっていきましょう。
すみません
本当にその通りでリンク先も読んでおきながら次のレスで
リンク先の現象=終了で回復
と思いこんでしまっていました。
せっかく的確なアドバイスを頂いたdeldelさんには申し訳ないです。