AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Memory Leak bei Interface Delegation

Ein Thema von dpg123 · begonnen am 27. Okt 2016 · letzter Beitrag vom 26. Jul 2019
Antwort Antwort
Seite 1 von 2  1 2   
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#1

Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 10:02
Delphi-Version: 2006
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:

type

  IMyInterface = interface

  end;

  TMyClass = class(TInterfacedObject, IMyInterface)

  end;

  TMyWrapper = class(TInterfacedObject, IMyInterface)

    FMyInterface: IMyInterface;

    property MyInterface: IMyInterface read FMyInterface implements IMyInterface;

  end;
Aufruf:

Delphi-Quellcode:
procedure Test;

var
  MyInterface: IMyInterface;

begin

  MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak

// MyInterface := TMyClass .Create(); // <- mit dieser Zeile KEIN Memory Leak

end;
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...

FastMM meldet:

Zitat:
---------------------------
Test.exe: Memory Leak Detected
---------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):

5 - 12 bytes: TMyWrapper x 1
Was mache ich falsch? Mit FMyInterface passiert nichts, es gibt keinen Zugriff auf die property. Wo ist der Unterschied zur TMyClass-Zeile, bei der das Reference Counting funktioniert? Wie delegiere ich richtig?

Dank und Gruß!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
35.189 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 10:10
[edit] falsch geguckt.

Hier auch?
Delphi-Quellcode:
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;
Und was ist hier?
Zitat:
procedure Test;
var
MyInterface: IMyInterface;
begin
MyInterface := TMyWrapper.Create(); // <- mit dieser Zeile Memory Leak
// MyInterface := TMyClass .Create(); // <- mit dieser Zeile KEIN Memory Leak

MyInterface := nil;
end;
Am Besten niemals mit globalen Variablen und nicht in der Mainfunction testen.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (27. Okt 2016 um 10:21 Uhr)
  Mit Zitat antworten Zitat
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#3

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 10:17
Hat leider beides nicht geholfen...

globale Variablen hab ich nicht... alles lokal im FormCreate-Event.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
35.189 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 10:44
Joar, hatte irgendwie das procedure als project gelesen.

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 end; ) immernoch über 0, womit die Isntanz natürlich nicht freigegeben wird.

So property MyInterface: IMyInterface read FMyInterface ;//implements IMyInterface; gibt es kein Leck.

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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
7.340 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 11:21
Es liegt am Implements.
Aus irgendeinem Grund besitzt TMyWrapper zwei Referenzen, anstatt nur Einer.
Das liegt daran, daß eine Bedingung für die Aggregation verletzt wird:
Zitat:
Die zweite IInterface-Implementierung delegiert Aufrufe für QueryInterface, _AddRef, und _Release an das äußere Objekt. Die äußere IInterface-Implementierung wird als Controlling Unknown bezeichnet.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
644 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#6

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 11:50
Hier noch ein paar Infos:

AggregatedObject


Stackoverflow


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.
Fritz Westermann
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
35.189 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 12:16
[F1] auf Delphi-Referenz durchsuchenimplements nennt zuerst die Variante mit dem Interface als Property und danach eine mit der Klasse.

Woebei die Klasse da nichtmal ein Interface ist, laut dem gezeigten Beispiel.
http://docwiki.embarcadero.com/RADSt..._Typ_Interface
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 )
Delphi-Quellcode:
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;
Mit der Klasse als interface hab ich kein Speicherleck.
Delphi-Quellcode:
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;
Die Klasse als Klasse funktioniert auch.
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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (27. Okt 2016 um 12:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
7.413 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: Memory Leak bei Interface Delegation

  Alt 27. Okt 2016, 12:55
(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)
Deshalb sollte man auch möglichst keine Interfaces auf TComponent-Nachkommen selbst nutzen. Wir haben z.B. ein GUI-Interface, das durch eine separate Klasse implementiert wird, die die visuelle Komponente lediglich kennt. Wird diese freigegeben, entfernt sie die Referenz, aber das separate Objekt bleibt bestehen. (Und leitet Zugriffe schlicht nicht mehr weiter.)
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
7.340 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Memory Leak bei Interface Delegation

  Alt 28. Okt 2016, 00:06
Woebei die Klasse da nichtmal ein Interface ist, laut dem gezeigten Beispiel.
Weil die Klasse das Interface zwar implementieren, aber es nicht auch noch unterstützen muss.

Das implements ist sogar noch flexibler:
Die Klasse, die bei dem implements steht, muss gar nicht das gesamte Interface implementieren. Es genügt, wenn die fehlenden Methoden von der Wrapper-Klasse implementiert werden.

Delphi-Quellcode:
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;
Das geht sogar noch weiter: Sollten beide Klassen eine Methode des Interfaces implementieren, dann hat die Implementation der Wrapper-Klasse Vorrang.

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;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
644 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#10

AW: Memory Leak bei Interface Delegation

  Alt 28. Okt 2016, 09:20
Zitat:
Das geht sogar noch weiter: Sollten beide Klassen eine Methode des Interfaces implementieren, dann hat die Implementation der Wrapper-Klasse Vorrang.

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;
Ja das ist schon interessant, aber in meinen Augen auch nicht sehr übersichtlich. Versuch das mal einem nicht Delphianer beizubringen.
Wenn das property auch als interface deklariert wird gewinnt das property...
Muss man wissen oder leidvoll erfahren.
Fritz Westermann
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:32 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf