TList, TMenuItemの項目のメモリ開放について

解決


kuze  2013-07-14 10:42:17  No: 44838

いつもお世話になっております。記憶があいまいになってきたので教えてください。
TObjectで継承されたクラスはある程度自動でメモリ開放をしてくれるのを期待しているのですが、下記の方法はメモリリークしないでしょうか?教えてください。

M, A: TMenuItem です。
L: TList です。

質問1
M.Add(TMenuItem.Create(M));   // TMenuItemの項目を追加
M[0] := nil;                  // 先ほど追加した項目の削除。ここで先ほど作成したTMenuItemは自動的にメモリが開放されるのでしょうか?

質問2
M.Add(TMenuItem.Create(M));   // TMenuItemの項目を追加
M.Clear;                      // 先ほど追加した項目の削除。ここで先ほど作成したTMenuItemは自動的にメモリが開放されるのでしょうか?

質問3
L.Add(TObject.Create);        // TObjectの項目を追加
L[0]:=nil;                    // 先ほど追加した項目の削除。ここで先ほど作成したTObjectは自動的にメモリが開放されるのでしょうか?

質問4
L.Add(TObject.Create);        // TObjectの項目を追加
L.Clear;                    // 先ほど追加した項目の削除。ここで先ほど作成したTObjectは自動的にメモリが開放されるのでしょうか?


kuze  2013-07-14 10:54:34  No: 44839

質問1は、おかしいですね。
TMenuItem.Itemsは、読み込み専用なので、
TMenuItem[0] := nil;
というように、nilを書き込みできませんね。すみません。
質問2以降を、質問とさせてください。


  2013-07-15 02:51:34  No: 44840

Clearとかnil代入後、そのオブジェクトにアクセスできるかどうか、
チェックするとはっきりするのではないでしょうか。

(例えばShowMessage(MenuItem.Name)とかで、オブジェクトが生きて
いるかどうかチェックする)

ためしてはいないのですが、Clearしただけでは、単純にオブジェクト
への参照が切れるだけで、オブジェクトの本体は生きているような
気がします。


Mr.XRAY  2013-07-15 05:58:29  No: 44841

>下記の方法はメモリリークしないでしょうか?教えてください。

手間を惜しまず,次のような簡単なテストプログラムを作成して,
実際に自分で,メモリリークが発生するか確認してみるのがいいと思いますよ.

//---------------------------------------------------------
//  注意: このままのコードではコンパイル時にエラーとなります
//        実際にコンパイルできないことを確認しています
//---------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
  L : TList;
begin
  ....

  L.Add(TObject.Create);

  ...

  L.Clear;

  ...

end;


tor  2013-07-15 06:05:35  No: 44842

まず、一般にnilを代入するのと削除は異なります。
代入するのは参照先を別のオブジェクトに差し替えているだけですから、むしろ「あえて削除せずにリストから外したい」という場合の書き方かと思います。

Clearに関してですが、TMenuItemのClearは「すべてのメニュー項目を削除および解放します」とヘルプで説明してありますね。

一方、TListのClearは単に配列の使用しているメモリを解放するだけです。
これはヘルプの説明だけ見てもはっきりしないかもしれませんが、
一般論としてTListはポインタの配列を管理するだけで、そのポインタが指している先までは面倒を見ません。
で、そういうTObjectの寿命管理までしてもらいたい場合は、TObjectListをOwnsObject=trueにして使います。


kuze  2013-07-15 20:03:26  No: 44843

Mr.XRAYさん
テストプログラムをなんとか試せれるようにします。
MemCheckを今まで使用したことがないのですが、チャレンジしてみます。
あさんの試し方は、確認方法が難しいです。
すべての変数からの参照がなくなったときに、TObjectが自動でメモリリークするかどうかを知りたいので、Clear前に他の変数で、TObjectを参照できるように準備した時点で、メモリ開放されるか確認できなくなります。
record型はメモリが開放されないのは理解しているので、自力でメモリ開放が必要と思っています。
torさん、TObjectListの存在は初めて知ったので参考になりました。


  2013-07-15 23:39:48  No: 44844

お話が分かりました。変数保持が不要になったとき、それが自動で
破棄される、ガベージコレクションのような機能があるのかを確認
されたいということですね。読み違えていました。すみません。


kuze  2013-07-17 08:19:29  No: 44845

遅くなりましたが確認しました。

質問2
M.Add(TMenuItem.Create(M));   // TMenuItemの項目を追加
M.Clear;                      // 先ほど追加した項目の削除。ここで先ほど作成したTMenuItemは自動的にメモリが開放されるのでしょうか?

メモリは開放されます。
というよりM.Clearすらする必要もなく、Form終了時にメモリ開放されるようです。
ただし、MのOwnerが、Formなどになっている必要があります。
オーナーのメモリが解放されると,その所有コンポーネントのメモリも解放される。つまり,フォームが破棄されると,フォーム上のコンポーネントもすべて破棄されます。
  

質問3
L.Add(TObject.Create);        // TObjectの項目を追加
L[0]:=nil;                    // 先ほど追加した項目の削除。ここで先ほど作成したTObjectは自動的にメモリが開放されるのでしょうか?

メモリリークします。
ただし、
L.Add(TComponent.Create(Self));
の場合は、Ownerがセットされるため、Form終了時にメモリリークは
発生しません。

質問4
L.Add(TObject.Create);        // TObjectの項目を追加
L.Clear;                    // 先ほど追加した項目の削除。ここで先ほど作成したTObjectは自動的にメモリが開放されるのでしょうか?

メモリリークします。
メモリリークを簡単に回避するには、TComponentを継承したClassを
用いると良いようです。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加