![]() |
MemoryLeak bei TList<IMyInterface>
Hi,
ich bin noch nicht dazu gekommen, genauer nachzugraben - aber vielleicht ist das Problem ja auch direkt bekannt? Ich arbeite mit XE3 an einem Projekt, das intensiv Interfaces benutzt. Jetzt zeigt mir EurekaLog ein Speicherleck. Ich konnte das soweit eingrenzen, dass es wohl an einer generischen Liste liegen muss:
Delphi-Quellcode:
Ich bin davon ausgegangen, dass der Referenzzähler des Eintrags dann runter gezählt und das Objekt hinter dem Interface freigegeben wird. Das ist aber nicht der Fall.
List := TList<IMyInterface>.Create;
List.Add(aInterface); List.Free; Ich habe es auch mal (war schon in der Nacht) dann mal mit
Delphi-Quellcode:
versucht - auch ohne Erfolg.
List[0] := nil
Ich bin noch nicht dazu gekommen, das mal in einem Testprojekt nachzubauen (kann ich erst heute Abend). Aber schon mal an Euch die Frage: Mache ich einen Denkfehler oder ist das ein XE3-Bug oder bemeckert das EurekaLog zu Unrecht (wobei der Destruktor des Objektes offenbar wirklich nicht aufgerufen wurde)? |
AW: MemoryLeak bei TList<IMyInterface>
Zitat:
Delphi-Quellcode:
Mavarik
IFoo = Interface
['{FD7BFFD9-1F75-4580-8C4A-375223FA0953}'] End; TFoo = Class(TInterfacedObject,IFoo) Public Procedure beforeDestruction;Override; end; var Form37: TForm37; implementation Uses System.Generics.Collections; {$R *.dfm} procedure TForm37.Button1Click(Sender: TObject); var Foo : IFoo; List : TList<IFoo>; begin Foo := TFoo.Create; List := TList<IFoo>.Create; List.add(Foo); List.free; end; { TFoo } procedure TFoo.beforeDestruction; begin Form37.Caption := 'Free!'; Inherited; end; |
AW: MemoryLeak bei TList<IMyInterface>
Woher kommt denn das aInterface? Wenn Du es als Parameter reingibst, könnte es von draussen noch Referenzen haben. Lokal erzeugt (wie im Beispiel von Mavarik) gibt es kein Leck.
|
AW: MemoryLeak bei TList<IMyInterface>
So ist das:
Delphi-Quellcode:
TFoo = class( TInterfacedObject )
end; procedure fooLeak( aInterface : IInterface ); begin end; procedure fooNoLeak( aInterface : IInterface ); var LRef : IInterface; begin LRef := aInterface; end; procedure bar; begin fooLeak( TFoo.Create ); fooNoLeak( TFoo.Create ); end; |
AW: MemoryLeak bei TList<IMyInterface>
Es gibt im Projekt einige Querverbindungen.
Aber wenn ich das List.Add mal rausnehme passt offenbar alles. Ich werde das heute Abend mal weiter untersuchen. Gestern bin ich daran etwas verzeifelt. Hätte ja sein können, dass da ein Bug bekannt wäre oder ich einen generellen Denkfehler hätte. |
AW: MemoryLeak bei TList<IMyInterface>
Mit diesen Querverbindungen hat es aber nichts zu tun.
Ursache ist einzig und allein, das hier
Delphi-Quellcode:
. Dabei wird nämlich kein RefCount erhöht!
foo( TFoo.Create );
|
AW: MemoryLeak bei TList<IMyInterface>
@Sir
Ich hatte vorhin keinen roten Kasten... Heißt das, wenn ich Interface-Parameter in einer Methode nicht benutzt wird gibt es ein MemoryLeak? Das wäre ja eine sehr unschöne Sache. Nach meiner derzeitigen Einschätzung dürfte das aber nicht das vorliegende Problem sein, da ich das Speicherleck vermeiden kann, indem ich die Anseisung List.Add(aInterface) auskommentiere. Mir fällt zwar gerade ein, dass ich wohl List.Add(MyObject) hinzufüge, aber das müsste ja problemlos dennoch das Interface verwalten. Oder wäre es besser, in einem solchen Fall explizit zu casten: List.Add(MyObject as IMyInterface)? Oder sollte man sogar unbedingt eine temporäre Interface-Variable anlagen und verwenden? PS: Dein eben nachgeschobenes Construkt verwende ich definiv nicht. Mal sehen, genaueres dann heute Abend... |
AW: MemoryLeak bei TList<IMyInterface>
Es heisst ganz einfach:
Wenn ich eine Instanz erzeuge und das direkt als ein Argument/Parameter übergebe, dann springt der Referenzzähler nicht an.
Delphi-Quellcode:
IFoo = interface
procedure Bar; end; procedure foo( aFoo : IFoo ); begin aFoo.Bar; end; var LFoo : IInterface; LFooObj : TFoo; foo( TFoo.Create ); // aufpassen, hier kann es zu einem Leak kommen LFoo := TFoo.Create; foo( LFoo ); // alles in Butter LFooObj := TFoo.Create; foo( LFooObj ); // aufpassen, hier wird auch keine Referenz erhöht! |
AW: MemoryLeak bei TList<IMyInterface>
Das ist dann aber ein Bug?
Hier
Delphi-Quellcode:
muß die Referenzzählung hoch gehn
procedure foo( aFoo : IFoo );
und hier
Delphi-Quellcode:
natürlich nicht.
procedure foo( const aFoo : IFoo );
Innerhalb der letzten Methode hat man dann viel Spaß, sobald der Zähler das erste Mal wieder auf 0 fällt. Und ohne referenzzählenden Zugriff, auf den Parameter, gibt es ein schönes Speicherleck. |
AW: MemoryLeak bei TList<IMyInterface>
@himitsu
Stimmt ... das
Delphi-Quellcode:
ist der Üpeltäter
const
Delphi-Quellcode:
ergibt bis zum abschließenden
program dp_184063;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IFoo = interface ['{FEF0782C-9F48-4060-A79D-8697F8431718}'] procedure Bar; end; TFoo = class( TInterfacedObject, IFoo ) private FName: string; public constructor Create( const Name: string ); destructor Destroy; override; procedure Bar; end; { TFoo } constructor TFoo.Create( const Name: string ); begin inherited Create; FName := Name; WriteLn( 'TFoo(', FName, ').Create' ); end; destructor TFoo.Destroy; begin WriteLn( 'TFoo(', FName, ').Destroy' ); inherited; end; procedure TFoo.Bar; begin WriteLn( 'TFoo(', FName, ').Bar' ); end; procedure CallConstFoo( const aFoo: IFoo ); begin aFoo.Bar; end; procedure CallFoo( aFoo: IFoo ); begin aFoo.Bar; end; procedure Test; begin CallConstFoo( TFoo.Create( 'ConstFoo' ) ); CallFoo( TFoo.Create( 'Foo' ) ); end; begin ReportMemoryLeaksOnShutdown := True; try Test; except on E: Exception do WriteLn( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Delphi-Quellcode:
ReadLn
Code:
und somit einen MemLeak für die ConstFoo benannte Instanz
TFoo(ConstFoo).Create
TFoo(ConstFoo).Bar TFoo(Foo).Create TFoo(Foo).Bar TFoo(Foo).Destroy |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz