5

関数内でオブジェクトが作成され、関数が完了すると、オブジェクトが明示的に破棄されていない場合、オブジェクトはどうなりますか?

すべての変数は、スコープ外になったときに破棄する必要がありますか、それともスコープ外になったときに処理されますか?

たとえば、custom_function が呼び出された後、locallist はどうなるでしょうか?

function TForm1.custom_function(string: test_string): boolean;
var locallist: TStringList;
begin
  locallist := TStringList.Create;
  // do a bunch of stuff here, but don't destroy locallist
  return true;
end;
4

5 に答える 5

17

メモリリークが発生します。

適当なパターンは

myObject := TObject.Create;
try
  //do stuff
finally
  myObject.Free;
end;

また、後でオブジェクトが解放されたかどうかをテストする必要がある場合は、FreeAndNil(myObject) を使用します。変数も nil に設定されるため、後でテストできます。

于 2009-03-11T20:07:05.957 に答える
13

他のポスターが指摘したように、これらのオブジェクトは明示的に解放する必要があります。Ray が示したように、これは通常、try..finally ブロックを使用して手動で行われます。ただし、知っておくべき例外があります。

コンポーネント (TComponent の子孫) は、そのコンストラクタに Owner パラメータを渡します。所有者がnilでない場合、所有者コンポーネントは新しいコンポーネントの所有権を取得し、解放されるとそれを解放します。これが、独自のフォームをクリーンアップする必要がない理由です。それらは Application オブジェクトに接続されており、プログラムの終了時に自分自身を解放する方法を知っています。ただし、実行時にコンポーネントを作成する場合は、所有者を割り当てるか、コンストラクターに nilを渡してから自分で解放する必要があります。コンポーネントを所有者で解放することによって、2 つを混在させないでください。 これにより、特定の状況下でダブルフリー状態が発生する可能性があります。

参照カウントを実装するインターフェース化されたオブジェクト (主に TInterfacedObject の子孫) は、(オブジェクトとしてではなく) 明確にインターフェースとして参照すると、参照カウント メカニズムによって解放されます。これらのオブジェクトへの最後のインターフェース参照が削除されると、それらは自動的に解放されます。すでにインターフェイス参照に割り当てている場合は、TInterfacedObject を手動で解放しないでください。これにより、例外が発生します。また、インターフェイスを持つすべてのオブジェクトが参照カウントを実装しているわけではないことに注意してください。ほとんどの場合、TInterfacedObject から派生したものだけです。

オブジェクトを作成し、try..finally ブロックを使用してから解放することは、必ずしも実用的ではありません。特に、オブジェクトをある種のリストに割り当てている (そしてそれらを大量に作成している) 場合は特にそうです。その場合は、TObjectList (または、OwnsObjects プロパティがtrueに設定された D2009 (TObjectList) をお持ちの場合はさらに良いでしょう。これにより、リストはその中のオブジェクトの所有者になり、コンポーネントが解放されるのと同じように、解放されると解放されます。繰り返しますが、オブジェクト リストによって所有されている場合は、オブジェクトを手動で解放しないでください。

動的配列 (文字列を含む) は、参照カウント システムを使用してコンパイラによって管理され、他のほとんどの型の変数はスタックに割り当てられます。ポインターをいじっていない限り、オブジェクト以外のものを手動で解放することを心配する必要はありません。

これはおそらく複雑に聞こえるかもしれませんが、すぐに慣れるでしょう。すべてのオブジェクトは、別のオブジェクト、インターフェイス参照カウント システム、またはコードのいずれかによって所有されていることを覚えておいてください。所有者は、不要になったオブジェクトをすべて解放する必要があります。他の何かによって所有されているものを解放しようとするべきではありません。(盗んではいけません。) これらのガイドラインを覚えておけば、適切なメモリ管理ができるようになります。DPR のメイン ルーチンで "ReportMemoryLeaksOnShutdown := true" を設定することもできます。

于 2009-03-11T21:06:53.050 に答える
5

メモリリークになります。

通常、このような割り当ては次のように囲む必要があります。

locallist := TStringList.Create;
try
     // work with locallist here
  finally
     locallist.Free;
  end; 

Delphi でスコープ外になると自殺行為になる参照は、インターフェイス参照だけです。

于 2009-03-11T19:27:56.830 に答える
3

記憶は取り戻されません、申し訳ありません。locallist.Free; を使用して、このオブジェクトを明示的に解放する必要があります。

于 2009-03-11T19:28:08.873 に答える
3

これにより、アプリケーションの終了時にのみ破棄されるメモリ リークが発生します。それらを検出するには、 FastMMなどのメモリ マネージャーを使用できます。

Destroy または Free メソッドを使用して、オブジェクトを破棄できることに注意してください。オブジェクトが nil の場合、前者はエラーを返しますが、後者はそうではありません。

if Assigned(Object) then Object.Destroy;
于 2009-03-11T19:28:27.170 に答える