Referenzzählung für Objekte

7

In meinem Code verwende ich eine kleine Datenspeicherklasse, die an verschiedenen Stellen erstellt wird. Um Speicherlecks zu vermeiden und Dinge zu vereinfachen, möchte ich die Referenzzählung verwenden, also tat ich

%Vor%

und entfernte alle meine manuellen Aufrufe zu TFileInfo.Free. Leider hat Delphi viele Speicherlecks gemeldet. Bei der Suche nach SO habe ich die folgende Frage gefunden, die erklärt, warum das nicht funktioniert:

Warum werden keine Nachkommen von TInterfacedObject-Garbage gesammelt?

Es gibt einen Workaround, der dort vorgestellt wird, aber es erfordert von mir (zumindest wenn ich es richtig verstehe), ein benutzerdefiniertes Interface IFileInfo zu schreiben und es mit einer Menge Getter und Setter zu versehen, die ich vermeiden möchte.

BEARBEITEN Ich sollte hinzufügen, dass ich die create FileInfo-Objekte in zwei verschiedene Arten von Hash-Tabellen einfüge: eine von TBucketList und eine Hash-Map-Implementierung aus dem Codegear-Forum. Intern sind sie beide Zeiger, so ist die Situation wie in der anderen Frage.

Gibt es eine andere Möglichkeit, Objekte in Delphi Referenzzählung zu verwenden?

    
jpfollenius 23.04.2009, 10:10
quelle

7 Antworten

5

Leider erzeugt der Delphi-Compiler nur dann den notwendigen Code, um die Anzahl der inc / dec-Referenzen zu ermitteln, wenn Sie Schnittstellen verwenden (in Ihrem Fall die benutzerdefinierte Schnittstelle IFileInfo). Wenn Schnittstellen in den Zeiger (oder auch in TObject) umgewandelt werden, ist außerdem keine Referenzzählung möglich. Zum Beispiel, Assumming globale Variablenliste: TList:

%Vor%

nachdem die Methode returns list [list.Count - 1] einen blinkenden Zeiger enthält.

So können Interfaces nicht in einer Hashmap verwendet werden, die sie in Pointer umwandelt, die Implementierung von hashmap muss sie als IInterface erhalten.

    
Kcats 23.04.2009, 10:42
quelle
8

Die Referenzzählung in Delphi funktioniert nur, wenn Sie nur über eine Schnittstelle auf Ihre Instanz verweisen. Sobald Sie Schnittstellenreferenzen und Klassenreferenzen mischen, sind Sie in Schwierigkeiten.

Im Wesentlichen möchten Sie eine Referenzzählung durchführen, ohne dass Sie eine Schnittstelle mit allen darin definierten Methoden und Eigenschaften erstellen müssen. Es gibt drei Möglichkeiten, dies zu tun, und diese sind ungefähr in der Reihenfolge, die ich ihnen empfehlen würde.

  1. Barry Kelly hat einen Beitrag über Smart Pointers geschrieben. Es verwendet die Generics in Delphi 2009, aber ich bin mir ziemlich sicher, dass Sie es hart auf die spezifischen Versionen des Typs codieren könnten, die Sie verwenden, wenn Sie 2009 noch nicht verwenden (es ist eine großartige Veröffentlichung BTW).

  2. Eine weitere Möglichkeit, die mit mehr Versionen von Delphi und weniger Modifikationen funktioniert, ist der Werttyp-Wrapper von Janez Atmapuri Makovsek. Es ist ein Beispiel für TStringList implementiert, aber Sie könnten es für jeden Typ anpassen.

  3. Der dritte Weg besteht darin, einen Schnittstellenzeiger zu erstellen (ähnlich dem Smart Pointer von Barry, aber nicht so intelligent). Ich glaube, es gibt einen in JCL, aber ich erinnere mich nicht an die Details. Im Grunde ist dies eine Schnittstelle, die eine TObject-Referenz bei der Konstruktion akzeptiert. Wenn der Referenzzähler null erreicht, ruft er das Objekt, das Sie ihm übergeben haben, kostenlos auf. Diese Methode funktioniert nur für kurzlebige Instanzen, die Sie nicht als Parameter übergeben, da Sie die Referenzzählung von der tatsächlich verwendeten Referenz trennen. Ich würde stattdessen eine der beiden anderen Methoden empfehlen, aber wenn Sie diese Methode bevorzugen und weitere Informationen wünschen, lassen Sie es mich wissen.

Das ist die Sache mit Delphi, es gibt freie Wege, Dinge zu erreichen. Option # 1 ist die beste meiner Meinung nach - Holen Sie Delphi 2009 und verwenden Sie diese Methode, wenn Sie können.

Viel Glück!

    
Jim McKeeth 23.04.2009 17:03
quelle
3

Wenn Sie Aufrufe von TObject-Instanzen für die Freigabe deaktivieren möchten, sollten Sie sich einen Speicherbereiniger für natives Delphi ansehen. Ich kenne 2 verschiedene Müllsammler und eine Müllsammeltechnik mit Vor- und Nachteilen.

Einer von denen wird wahrscheinlich für Sie arbeiten.

    
Jim McKeeth 23.04.2009 18:38
quelle
3

Mischen Sie keine Objektverweise und Schnittstellenreferenzen.

%Vor%     
Steffen Binas 23.04.2009 14:37
quelle
2

Diese Funktionalität wird für Schnittstellen bereitgestellt, nicht jedoch für Objekte.

Sie können so etwas erstellen, aber Sie müssen einige der Struktur von TObject überschreiben:

%Vor%

Sie müssen RefCountedCopy verwenden, um das Objekt einer anderen Variablen zuzuordnen. Aber dann haben Sie ein refcounted Objekt.

Wie man das benutzt:

%Vor%     
Toon Krijthe 23.04.2009 10:36
quelle
1

Um zu dem bereits Gesagten hinzuzufügen, verwenden Sie eine TInterfaceList , wenn Sie Verweise auf Schnittstellen speichern möchten, anstatt eine TList zu verwenden. Die ref count wird konsistent arbeiten.

    
François 23.04.2009 17:14
quelle
0

Es gibt eine lange Erklärung dafür, aber kurz gesagt: Wenn Sie TInterfacedObject vererben (und Free selbst nicht aufrufen), reicht das nicht aus, Sie müssen ein Objekt-Factory-Dynamic verwenden, um die Objekte für Sie zu erstellen, Zeiger auf das Objekt überall, nicht nur Objekt-Referenz-Variablen. (Ja, das bedeutet, Sie können nicht einfach "alten Code" wechseln, ohne es zu überdenken)

    
Stijn Sanders 23.04.2009 11:04
quelle