Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi TInterfacedObject wird nicht freigegeben (https://www.delphipraxis.net/179584-tinterfacedobject-wird-nicht-freigegeben.html)

Codehunter 18. Mär 2014 07:54

TInterfacedObject wird nicht freigegeben
 
Hallo!

Ich habe das Problem, dass ich so wie es aussieht mal wieder über den Referenzzähler bei Interfaces stolpere. Ich habe eine Komponente basierend auf TWebbrowser, welche ein HTML-Editor sein soll. Im OnDocumentComplete-Handler erzeuge ich ein TInterfacedObject zum Handling von Javascript-Events (was soweit auch alles funktioniert). Das einzige Problem ist, dass dieses TInterfacedObject genau einmal weniger freigegeben als instantiiert wird und folglich ein Memleak beim Programmende entsteht. Hier erstmal ein bisschen Code:
Delphi-Quellcode:
type
  THTMLEditor = class(TWebbrowser)
  private
    { private declarations }
    FKeyDownEvent: THtmlEvent;

{...}

procedure THTMLEditor.DoDocumentComplete(ASender: TObject;
  const pDisp: IDispatch; const URL: OleVariant);
begin
  GetDocument.body.style.borderStyle:= 'none';
  if HasDocument then begin
    FKeyDownEvent:= NIL; // <-- Ruft THtmlEvent.Destroy TATSÄCHLICH auf
    FKeyDownEvent:= THtmlEvent.Create;
    FKeyDownEvent.OnEvent:= DoKeyDownEvent;
    FKeyDownEvent.Document:= GetDocument;
    GetDocument.onkeypress:= FKeyDownEvent as IDispatch;
  end;
  EditMode:= TRUE;
end;

{...}

destructor THTMLEditor.Destroy;
begin
  FKeyDownEvent:= NIL; // <-- Wird bei Programmende ausgeführt
  FBodyHtml.Free;
  FInterfaceContainer.Free;
  inherited;
end;

{...}

type
  THtmlEvent = class(TInterfacedObject, IDispatch)
  {...}
  end;

{...}

destructor THtmlEvent.Destroy; // <-- Wird bei Programmende NICHT ausgeführt
begin
  FDocument:= NIL;
  inherited Destroy;
end;
Die Meldung von FastMM lautet, dass genau eine Instanz von THtmlEvent beim Programmende noch existierte und zwar egal wie viele Documents zwischendurch geladen und OnDocumentComplete aufgerufen wurde.

Sir Rufo 18. Mär 2014 07:57

AW: TInterfacedObject wird nicht freigegeben
 
Delphi-Quellcode:
FKeyDownEvent
ist vom Typ
Delphi-Quellcode:
THtmlEvent
, richtig?

Die Referenzzählung geht aber nur, wenn du mit dem Interface arbeitest und nicht mit dem Objekt

Bernhard Geyer 18. Mär 2014 08:00

AW: TInterfacedObject wird nicht freigegeben
 
Beim IE (TWEbBrowser) ist es Normal das die Implementierung die MS gemacht hat es nicht so genau mit der Freigabe der Interfaces nimmt.
Ich muss öfter direkt mal _Release-Aufrufen damit mir der Speicher nicht volläuft. Vermutlich vergisst der IE auch bei dir auch die entsrpechenden Release-Aufrufe.

Codehunter 18. Mär 2014 08:26

AW: TInterfacedObject wird nicht freigegeben
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1252356)
Ich muss öfter direkt mal _Release-Aufrufen damit mir der Speicher nicht volläuft. Vermutlich vergisst der IE auch bei dir auch die entsrpechenden Release-Aufrufe.

Das war die Lösung! Herzlichen Dank!

Sir Rufo 18. Mär 2014 08:38

AW: TInterfacedObject wird nicht freigegeben
 
Leider ist deine Annahme falsch
Delphi-Quellcode:
    FKeyDownEvent:= NIL; // <-- Ruft THtmlEvent.Destroy TATSÄCHLICH auf
    ...
    GetDocument.onkeypress:= FKeyDownEvent as IDispatch;
denn die Instanz wird freigegeben wegen
Delphi-Quellcode:
GetDocument.onkeypress:= FKeyDownEvent as IDispatch;

TiGü 18. Mär 2014 08:45

AW: TInterfacedObject wird nicht freigegeben
 
Delphi-Quellcode:
var YourObject : ...;

if YourObject.Type.BeginsWith.I then
  YourObject:= nil;

if YourObject.Type.BeginsWith.T then
  YourObject.Free;

Codehunter 18. Mär 2014 09:17

AW: TInterfacedObject wird nicht freigegeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1252358)
denn die Instanz wird freigegeben wegen
Delphi-Quellcode:
GetDocument.onkeypress:= FKeyDownEvent as IDispatch;

Haste Recht! Geht auch ganz ohne... Diese ganze Interfacerei ist nicht so mein Fall. Ich bin froh wenn ich mich mit Delphi native befassen und auf den eigenen Speichermanager verlassen kann. Aber manchmal gehts halt nicht ohne Interfaces. Wie in diesem Fall, denn zum IE im EditMode gibt es nach wie vor nicht wirklich eine Alternative.

Sir Rufo 18. Mär 2014 10:20

AW: TInterfacedObject wird nicht freigegeben
 
Zitat:

Zitat von TiGü (Beitrag 1252360)
Delphi-Quellcode:
var YourObject : ...;

if YourObject.Type.BeginsWith.I then
  Object := nil;

if YourObject.Type.BeginsWith.T then
  Object.Free;

Du hast da noch was vergessen
Delphi-Quellcode:
TMyClass = class( TInterfacedObject )
end;

var
  MyInstance : TMyClass;
  MyInterface : IInterface;

// das geht
MyInstance := TMyClass.Create;
MyInstance.Free;

// das knallt
MyInstance := TMyClass.Create;
MyInterface := MyInstance; // Referenz-Zähler auf 1
MyInterface := nil; // Referenz-Zähler auf 0 => Instanz wird freigeben
MyInstance.Free; // rumms

TiGü 19. Mär 2014 14:03

AW: TInterfacedObject wird nicht freigegeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1252368)
Du hast da noch was vergessen
Delphi-Quellcode:
TMyClass = class( TInterfacedObject )
end;

var
  MyInstance : TMyClass;
  MyInterface : IInterface;

// das geht
MyInstance := TMyClass.Create;
MyInstance.Free;

// das knallt
MyInstance := TMyClass.Create;
MyInterface := MyInstance; // Referenz-Zähler auf 1
MyInterface := nil; // Referenz-Zähler auf 0 => Instanz wird freigeben
MyInstance.Free; // rumms

Wer sowas macht hat es auch nicht anders verdient! :evil:

Sir Rufo 19. Mär 2014 14:06

AW: TInterfacedObject wird nicht freigegeben
 
Zitat:

Zitat von TiGü (Beitrag 1252554)
Zitat:

Zitat von Sir Rufo (Beitrag 1252368)
Du hast da noch was vergessen
Delphi-Quellcode:
TMyClass = class( TInterfacedObject )
end;

var
  MyInstance : TMyClass;
  MyInterface : IInterface;

// das geht
MyInstance := TMyClass.Create;
MyInstance.Free;

// das knallt
MyInstance := TMyClass.Create;
MyInterface := MyInstance; // Referenz-Zähler auf 1
MyInterface := nil; // Referenz-Zähler auf 0 => Instanz wird freigeben
MyInstance.Free; // rumms

Wer sowas macht hat es auch nicht anders verdient! :evil:

Die sogenannten weak Referenzen sind teilweise unumgänglich, da ansonsten auch Interfaces nicht korrekt freigegebn werden (zirkuläre Referenzen)


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:47 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz