![]() |
Interfaces werden nicht dereferenziert
Hallo zusammen,
ich hab ein kleines Problem mit meinem aktuellen Projekt: Um PlugIns unterstützen zu könne, habe ich meine Hauptobjekte in Interfaces umgebaut. Seit ich das gemacht habe hab ich ein riesengroßes Speicherleck (> 7MB nach dem Öffnen eines Dokuments). Meine Objekte sind hierarchisch organisiert (jedes Objekt besitzt einen Container (auch als Interface implementiert, Kapselung von TInterfaceList), in dem sich die Kind-Objekte befinden; das Ganze ist ähnlich wie bei nem TreeView). Wenn ich ein Dokument erstelle (Hauptobjekt + ein Unterobjekt), dann ist beim Beenden der Referenzzähler des Hauptobjekts irgendwo zwichen 12 und 100, auch wenn ich nichts sont mach (da sollte doch dann immer der gleiche Wert stehen :gruebel: ). Ich könnte jetzt natürlich überall schauen, wo ich das Objekt referenziere, aber da der Referenzzähler zwischendrinn auch mal > 1000 und mein Programm > 130.000 loc ist, sitze ich wahrscheinlich nächstes Jahr noch dran :? . Darum Folgendes: Gibt es eine einfache Möglichkeit, solche offenen Referenzen zu finden oder muss ich wirklich nen Spaten nehmen und graben? Danke für Antworten xaromz |
Re: Interfaces werden nicht dereferenziert
spateln ist immer gut ;)
Delphi-Quellcode:
es sei denn du machsts so
var
xInterface: IWhatever; begin if Assigned(xInterface) then xInterface := nil; end;
Delphi-Quellcode:
var
xObj: TWhatever; begin xObj := TWhatever.Create As IWhatever; try finally FreeAndNil(xObj); end; end; |
Re: Interfaces werden nicht dereferenziert
Hallo,
Zitat:
Als das noch einfache Delphi-Objekte waren war das ja egal, bzw. Delphi hat sogar gemeckert (Hinweis:...wird nie benutzt) wenn man das Objekt auf nil gesetzt hat. Warum bringt Delphi keine Warnung, wenn man ein Interface benutzt und nicht wieder freigibt? Noch was: Wenn ich mir ein Interface so hole
Delphi-Quellcode:
wird dann das Interface von Delphi automatisch wieder freigegeben?
if (XXX as IMyInterface).IrgendeinProperty = True then
... Gruß xaromz |
Re: Interfaces werden nicht dereferenziert
Zitat:
Ich kenne 3 Möglichkeiten dass die Referenzzählung nicht korrekt arbeitet: 1.) speichern von Interfacepointern in "normalen" Pointer. Man muss mit AddRef nachhelfen, sonst wird das Objekt freigeben
Delphi-Quellcode:
2.) Manchmal implementiert man die Methoden _AddRef und _Release in eigenen Klassen, damit man
var
ob : Pointer; lg : ILogger; begin lg := CoLogger.Create; // object erzeugen // RefCount ist 1 lg._AddRef; // RefCount ist 2 ob := lg; end; // RefCount ist wieder 1 // Wenn nun der Pointer "ob" beschrieben wird ohne vorher ._Release aufzurufen // hast du ein Speicherleck nicht von TInterfacedObject erben muss. Wenn hier etwas falsch macht, ist die Referenzzählung ausser Kraft gesetzt -> Speicherleck 3.) Vermischung von Objekt- und Interfacereferenzen Deine Objekte lassen sich in Objekt-Zeigern (abgeleitet von TObject) oder in Interfacezeigern (abgeleitet von IUnknown) speichern. Wenn man beim gleichen Objekt beide Arten anwendet, kommt man in Schwierigkeiten. |
Re: Interfaces werden nicht dereferenziert
Hallo,
danke für die Antwort. Ich erstelle natürlich ein Objekt und speichere es dann nur noch als Interface bzw. in einer TInterfaceList. Also sollte es keine Vermischung TObject <> IInterface bzw. Pointer <> IInterface geben. Inzwischen bin ich auch dabei meine Referenzen zu überprüfen. Es ist doch erstaunlich, wie oft man so ein Objekt zuweist... Aber wo wir schon dabei sind, wie sieht es eigentlich hiermit aus:
Delphi-Quellcode:
Muss bei *** ein
var
I: IInterface; List: TInterfaceList; C: Integer; begin for C := 0 to List.Count - 1 do begin I := List[C]; // Tu was mit I // *** end; end;
Delphi-Quellcode:
stehen oder erkennt Delphi hier die Zuweisung auf eine bereits "gefüllte" Variable und gibt das vorherige Interface frei? Ich vermute mal nein, oder?
I := nil;
Gruß xaromz |
Re: Interfaces werden nicht dereferenziert
Ich füge zu der Liste noch das klassische Problem von Referenzzählung hinzu:
Dein Problem ist, dass eine Interface instanz eine Interface instanz besitzt, die eine Referenz auf die Container instanz hält, right? Mit RefCounting lässt sich dieser Zustand nicht elegant lösen. Beiden halten somit mindestens ein Referenz (sich gegenseitig) obwohl sie vielleicht schon beide vom Programm aus nicht mehr referenziert werden können. Eine billige Lösung wäre TAggregatedObject als Basisklasse für das untergeordnete Element. Dabei werden AddRef/Release zum Controller durchgeschliffen. Aber auch das ist nur ein dummer Hack. Ein Release auf den Controller wird kein Release des Aggregatfeldes auslösen und somit ist nicht sichergestellt, dass es mit freigegeben wird. Außerdem gibt es keinerlei Garantie dass es immer geht, denn du wirst oft feststellen dass in solchen Situationen...
Delphi-Quellcode:
... weder Controller noch Dingsbums freigegeben werden _könnten_.
begin
with ControllerFactory.GetController do GetDingsBums.DoSomething(); end; Vielleicht bin ich als .Net Entwickler zu verwöhnt um mir wegen solchen dummen Kleinigkeiten wie RefCounting die Laune vermiesen zu lassen. Aber wenn das ein neues Projekt wird, dann nehme .Net solange es dir noch möglich ist. Diese Spielereien mit Interfaces unm explizites Freigeben zu verhindern sind ja ganz nett (selbst oft genutzt..). Aber IMHO viel zu nervig als eine Garbage Collection, die kein RefCounting braucht... |
Re: Interfaces werden nicht dereferenziert
Zitat:
Es spielt keine Rolle, ob bei der Zuweisung nil oder ein neuer Wert gesetzt wird. (also braucht du die Zeile mit *** nicht)
Delphi-Quellcode:
// Pseudocode
procedure InterfacePointerZuweisung(var oldptr, newptr:Pointer); begin if oldptr=newptr then // keine Ahnung, ob Delphi dies beachtet; ich würd's so machen Exit; if oldptr <> nil then IUnknown(oldptr)._Release; oldptr := newptr; end; |
Re: Interfaces werden nicht dereferenziert
Hallo,
Zitat:
Das automatische Freigeben ist ein Feature, das ich eigentlich gar nicht brauche (das im Gegenteil eher lästig ist, daher ja dieser Thread). Explizites Freigeben hat bisher gut funktioniert, ist jetzt aber natürlich nicht mehr möglich. Gruß xaromz |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:10 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