![]() |
Delphi-Version: 2006
Memory Leak bei Interface Delegation
Hello zusammen,
arbeite mich gerade in das Thema Interfaces, deren Delegation und Reference Counting ein. Beim Experimentieren bin ich auf folgendes Minimalbsp gestoßen, bei dem mir FastMM ein Memory Leak anzeigt und ich habe keinen Schimmer warum und wie ich es weg bekomme
Delphi-Quellcode:
Aufruf:type IMyInterface = interface end; TMyClass = class(TInterfacedObject, IMyInterface) end; TMyWrapper = class(TInterfacedObject, IMyInterface) FMyInterface: IMyInterface; property MyInterface: IMyInterface read FMyInterface implements IMyInterface; end;
Delphi-Quellcode:
Man beachte, dass ich mit FMyInterface in TMyWrapper noch nichts gemacht habe! Alleine durch das Deklarieren der Property geht anscheinend iwas beim Reference Counting schief...
procedure Test;
var MyInterface: IMyInterface; begin MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak // MyInterface := TMyClass .Create(); // <- mit dieser Zeile KEIN Memory Leak end; FastMM meldet: Zitat:
Dank und Gruß! |
AW: Memory Leak bei Interface Delegation
[edit] falsch geguckt.
Hier auch?
Delphi-Quellcode:
Und was ist hier?
procedure Test;
procedure TestProc; var MyInterface: IMyInterface; begin MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak //MyInterface := TMyClass .Create(); // <- mit dieser Zeile KEIN Memory Leak end; begin TestProc; end; Zitat:
|
AW: Memory Leak bei Interface Delegation
Hat leider beides nicht geholfen...
globale Variablen hab ich nicht... alles lokal im FormCreate-Event. |
AW: Memory Leak bei Interface Delegation
Joar, hatte irgendwie das procedure als project gelesen. :oops:
Aaaaaaaaalso, im XE das Selbe. Es liegt am Implements. Aus irgendeinem Grund besitzt TMyWrapper zwei Referenzen, anstatt nur Einer. Und da es nur eine Variable und auch keine "versteckte" Tempvariable gibt, steht RefCount am Ende (nach __Release im
Delphi-Quellcode:
) immernoch über 0, womit die Isntanz natürlich nicht freigegeben wird.
end;
So
Delphi-Quellcode:
gibt es kein Leck.
property MyInterface: IMyInterface read FMyInterface ;//implements IMyInterface;
PS: Du hast vergessen der innere Interface zu erstellen. So knallt das wunderschön, wenn man auf irgendwas von IInterface oder IMyInterface zugreifen will, da diese Referenz NIL ist.
Delphi-Quellcode:
type
IMyInterface = interface procedure ShowRefCount; end; TMyClass = class(TInterfacedObject, IMyInterface) procedure ShowRefCount; end; TMyWrapper = class(TInterfacedObject, IMyInterface) FMyInterface: IMyInterface; constructor Create; property MyInterface: IMyInterface read FMyInterface implements IMyInterface; end; procedure TMyClass.ShowRefCount; begin ShowMessage(IntToStr(RefCount)); end; constructor TMyWrapper.Create; begin inherited; FMyInterface := TMyClass.Create; end; procedure TForm4.FormCreate(Sender: TObject); var MyInterface: IMyInterface; begin ReportMemoryLeaksOnShutdown := True; MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak //MyInterface := TMyClass.Create(); // <- mit dieser Zeile KEIN Memory Leak //ShowMessage(IntToStr((MyInterface as TInterfacedObject).RefCount)); MyInterface.ShowRefCount; end; |
AW: Memory Leak bei Interface Delegation
Zitat:
![]() Zitat:
|
AW: Memory Leak bei Interface Delegation
Hier noch ein paar Infos:
![]() ![]()
Delphi-Quellcode:
unit Unit1;
interface type IMyInterface = interface procedure ShowInfo; end; // Ableiten von TAggregatedObject TMyClass = class(TAggregatedObject, IMyInterface) procedure ShowInfo; end; TMyWrapper = class(TInterfacedObject, IMyInterface) private // Wir "besitzen" also die Klasse selber speichern FMyClass: TMyClass; function getMyInterface: IMyInterface; public constructor Create; destructor Destroy; override; property MyInterface: IMyInterface read getMyInterface implements IMyInterface; end; procedure Test; implementation uses System.SysUtils; procedure TMyClass.ShowInfo; begin writeln('Call ShowInfo'); end; constructor TMyWrapper.Create; begin inherited; FMyClass := TMyClass.Create(self); end; destructor TMyWrapper.Destroy; begin inherited; // Klasse freigeben FMyClass.Free; end; function TMyWrapper.getMyInterface: IMyInterface; begin result := FMyClass as IMyInterface; end; procedure Test; var MyInterface: IMyInterface; begin MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak MyInterface.ShowInfo; // Kein Leak :-) end; end. |
AW: Memory Leak bei Interface Delegation
[F1] auf
![]() Woebei die Klasse da nichtmal ein Interface ist, laut dem gezeigten Beispiel. ![]() Die OH verwendet auch nirgendwo einen Getter, der auf dem Object ein Interface macht, beim Zugrif. Und nach meinem Verständnis sollte man eigentlich eh niemals Interface-Referenzen mit Objekt-Referenzen auf das selbe Objekt mischen? (Ausnahme die TComponents, welche nicht referenzgezählt sind, auch wenn das schon ein bissl krank ist, denn das knallt, wenn man ein Free macht, bevor die letzte Interfacereferenz freigegeben wurde) Beides vom Typ Interface und ich hab diesmal zwei Speicherlecks. (TInterfacedObject statt TAggregatedObject ergab nur ein Speicherleck :stupid:)
Delphi-Quellcode:
Mit der Klasse als interface hab ich kein Speicherleck. :cyclops:
type
IMyInterface = interface procedure Show; end; TMyClass = class(TAggregatedObject, IMyInterface) procedure Show; end; TMyWrapper = class(TInterfacedObject, IMyInterface) private FMyInterface: IMyInterface; public constructor Create; property MyInterface: IMyInterface read FMyInterface implements IMyInterface; end; procedure TMyClass.Show; begin ShowMessage('blubb'); end; constructor TMyWrapper.Create; begin inherited; FMyInterface := TMyClass.Create(Self); end; procedure TForm4.FormCreate(Sender: TObject); var MyInterface: IMyInterface; begin ReportMemoryLeaksOnShutdown := True; MyInterface := TMyWrapper.Create; MyInterface.Show; end;
Delphi-Quellcode:
Die Klasse als Klasse funktioniert auch.
type
IMyInterface = interface procedure Show; end; TMyClass = class(TAggregatedObject, IMyInterface) procedure Show; end; TMyWrapper = class(TInterfacedObject, IMyInterface) private FMyClass: TMyClass; public constructor Create; destructor Destroy; override; property MyInterface: TMyClass read FMyClass implements IMyInterface; end; procedure TMyClass.Show; begin ShowMessage('blubb'); end; constructor TMyWrapper.Create; begin inherited; FMyClass := TMyClass.Create(Self); end; destructor TMyWrapper.Destroy; begin FMyClass.Free; inherited; end; procedure TForm4.FormCreate(Sender: TObject); var MyInterface: IMyInterface; begin ReportMemoryLeaksOnShutdown := True; MyInterface := TMyWrapper.Create; MyInterface.Show; end;
Delphi-Quellcode:
type
IMyInterface = interface procedure Show; end; TMyClass = class procedure Show; end; TMyWrapper = class(TInterfacedObject, IMyInterface) private FMyClass: TMyClass; public constructor Create; destructor Destroy; override; property MyInterface: TMyClass read FMyClass implements IMyInterface; end; procedure TMyClass.Show; begin ShowMessage('blubb'); end; constructor TMyWrapper.Create; begin inherited; FMyClass := TMyClass.Create; end; destructor TMyWrapper.Destroy; begin FMyClass.Free; inherited; end; procedure TForm4.FormCreate(Sender: TObject); var MyInterface: IMyInterface; begin ReportMemoryLeaksOnShutdown := True; MyInterface := TMyWrapper.Create; MyInterface.Show; end; |
AW: Memory Leak bei Interface Delegation
Zitat:
|
AW: Memory Leak bei Interface Delegation
Zitat:
Das
Delphi-Quellcode:
ist sogar noch flexibler:
implements
Die Klasse, die bei dem
Delphi-Quellcode:
steht, muss gar nicht das gesamte Interface implementieren. Es genügt, wenn die fehlenden Methoden von der Wrapper-Klasse implementiert werden.
implements
Delphi-Quellcode:
Das geht sogar noch weiter: Sollten beide Klassen eine Methode des Interfaces implementieren, dann hat die Implementation der Wrapper-Klasse Vorrang.
type
IMyInterface = interface procedure Foo; procedure Bar; end; TMyClass = class protected procedure Foo; end; TMySuperClass = class(TInterfacedObject, IMyInterface) private FMyClass: TMyClass; function GetMyClass: TMyClass; protected procedure Bar; property MyClass: TMyClass read GetMyClass implements IMyInterface; public destructor Destroy; override; end;
Delphi-Quellcode:
type
IMyInterface = interface procedure Foo; procedure Bar; end; TMyClass = class protected procedure Foo; procedure Bar; end; TMySuperClass = class(TInterfacedObject, IMyInterface) private FMyClass: TMyClass; function GetMyClass: TMyClass; protected procedure Bar; // hat Vorrang for MyClass.Bar property MyClass: TMyClass read GetMyClass implements IMyInterface; public destructor Destroy; override; end; |
AW: Memory Leak bei Interface Delegation
Zitat:
Wenn das property auch als interface deklariert wird gewinnt das property... Muss man wissen oder leidvoll erfahren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:22 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-2025 by Thomas Breitkreuz