2009-03-11 5 views
4

関数と関数内で作成されたオブジェクトが完成すると、明示的に破棄されなかったオブジェクトはどうなりますか?デルファイのスコープから外れるオブジェクトには何が起こりますか?

すべての変数は、範囲外になるか、範囲外になったときに破棄する必要がありますか?

たとえば、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; 

答えて

16

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

適切なパターンを使用すると、オブジェクトが解放されている場合、後にテストする必要がある場合は、FreeAndNil(myObjectという)を使用しても

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

です。変数をnilに設定するので、後でテストすることもできます。

5

メモリがリークします。

あなたは一般的にこのような配分を囲む必要があります。

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

彼らはスコープの外にドロップしたときに自殺しているDelphiでの参照の唯一の種類は、インターフェースの参照です。

+0

と文字列参照とインターフェイス参照 –

+0

tryはtryの前にあります。常に。 – Ray

+0

これを使用すると、オブジェクトに警告が表示されます。作成が失敗する可能性があるため、オブジェクトは解放されようとします。 – Ray

3

メモリは再利用されません。申し訳ありません。 locallist.Freeを使用してこのオブジェクトを明示的に解放する必要があります。

3

この結果、memory leakがアプリケーションの最後でのみ破棄されます。それらを検出するには、FastMMのようなメモリマネージャを使用できます。

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

if Assigned(Object) then Object.Destroy; 
+0

そのようなFastMMツールは、アプリケーションにコンパイルされるものか、Delphiエディタ/コンパイラのアドオンのいくつかのタイプですか? – Dave

+0

これはアプリに組み込まれています。それをuses句に追加すると、プロジェクトに追加されます。これには2つの効果があります:1. Delphiのメモリルーチンの高速化、2.メモリリークの検出。プロジェクトがコンパイラで実行されると、メモリリークがスタックトレースと共に報告されます。 – schnaader

+0

私は、FastMMがDelphiの後のバージョンに組み込まれていると思っていました(とにかく高速化が進んでいます)。私は間違っている可能性がある。 – Ray

10

他のポスターと同様に、これらのオブジェクトを明示的に解放する必要があります。これは通常、try..finallyブロックを使用して手動で実行されます。しかし、あなたが知っておかなければならない例外があります。

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

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

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

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

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

+1

"所有者とコンポーネントを解放して2つを混在させないでください。これはダブルフリーの状態になります。"この繰り返しをやめてもいいですか?それは単に間違っている。所有者がコンポーネントを解放すると、所有者が保持する所有コンポーネントのリストからそのコンポーネントが削除されます。準最適であるか混乱しているかもしれません... – mghie

+0

しかし間違っているか危険です。詳細については、http://stackoverflow.com/questions/398137を参照してください。これは、他の良い答えから差し引きます。 – mghie

+0

どのように行われているかによって異なります。これは、私がコードを持っていたときに私が一度噛みました。そのコンポーネントを所有していたフォームが破棄された後に作成したコンポーネントを解放しようとしました。 (はい、これは一般的な条件ではありませんが、慎重でないと起こる可能性があります)しかし、少し編集します... –

関連する問題