Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi MemoryLeak bei TList<IMyInterface> (https://www.delphipraxis.net/184063-memoryleak-bei-tlist-imyinterface.html)

stahli 23. Feb 2015 11:33

MemoryLeak bei TList<IMyInterface>
 
Hi,

ich bin noch nicht dazu gekommen, genauer nachzugraben - aber vielleicht ist das Problem ja auch direkt bekannt?

Ich arbeite mit XE3 an einem Projekt, das intensiv Interfaces benutzt. Jetzt zeigt mir EurekaLog ein Speicherleck.
Ich konnte das soweit eingrenzen, dass es wohl an einer generischen Liste liegen muss:

Delphi-Quellcode:
List := TList<IMyInterface>.Create;
List.Add(aInterface);
List.Free;
Ich bin davon ausgegangen, dass der Referenzzähler des Eintrags dann runter gezählt und das Objekt hinter dem Interface freigegeben wird. Das ist aber nicht der Fall.

Ich habe es auch mal (war schon in der Nacht) dann mal mit
Delphi-Quellcode:
List[0] := nil
versucht - auch ohne Erfolg.


Ich bin noch nicht dazu gekommen, das mal in einem Testprojekt nachzubauen (kann ich erst heute Abend).

Aber schon mal an Euch die Frage: Mache ich einen Denkfehler oder ist das ein XE3-Bug oder bemeckert das EurekaLog zu Unrecht (wobei der Destruktor des Objektes offenbar wirklich nicht aufgerufen wurde)?

Mavarik 23. Feb 2015 12:10

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291083)
Ich bin noch nicht dazu gekommen, das mal in einem Testprojekt nachzubauen (kann ich erst heute Abend).

hmm mit XE7 kein Problem...

Delphi-Quellcode:
  IFoo = Interface
    ['{FD7BFFD9-1F75-4580-8C4A-375223FA0953}']
  End;

  TFoo = Class(TInterfacedObject,IFoo)
    Public
      Procedure beforeDestruction;Override;
  end;

var
  Form37: TForm37;

implementation

Uses System.Generics.Collections;

{$R *.dfm}

procedure TForm37.Button1Click(Sender: TObject);
var
  Foo : IFoo;
  List : TList<IFoo>;
begin
  Foo := TFoo.Create;
  List := TList<IFoo>.Create;
  List.add(Foo);
  List.free;
end;

{ TFoo }

procedure TFoo.beforeDestruction;
begin
  Form37.Caption := 'Free!';
  Inherited;
end;
Mavarik

Union 23. Feb 2015 12:17

AW: MemoryLeak bei TList<IMyInterface>
 
Woher kommt denn das aInterface? Wenn Du es als Parameter reingibst, könnte es von draussen noch Referenzen haben. Lokal erzeugt (wie im Beispiel von Mavarik) gibt es kein Leck.

Sir Rufo 23. Feb 2015 12:32

AW: MemoryLeak bei TList<IMyInterface>
 
So ist das:
Delphi-Quellcode:
TFoo = class( TInterfacedObject )
end;

procedure fooLeak( aInterface : IInterface );
begin

end;

procedure fooNoLeak( aInterface : IInterface );
var
  LRef : IInterface;
begin
  LRef := aInterface;

end;

procedure bar;
begin
  fooLeak( TFoo.Create );
  fooNoLeak( TFoo.Create );
end;

stahli 23. Feb 2015 12:36

AW: MemoryLeak bei TList<IMyInterface>
 
Es gibt im Projekt einige Querverbindungen.
Aber wenn ich das List.Add mal rausnehme passt offenbar alles.

Ich werde das heute Abend mal weiter untersuchen. Gestern bin ich daran etwas verzeifelt.

Hätte ja sein können, dass da ein Bug bekannt wäre oder ich einen generellen Denkfehler hätte.

Sir Rufo 23. Feb 2015 12:54

AW: MemoryLeak bei TList<IMyInterface>
 
Mit diesen Querverbindungen hat es aber nichts zu tun.

Ursache ist einzig und allein, das hier
Delphi-Quellcode:
foo( TFoo.Create );
. Dabei wird nämlich kein RefCount erhöht!

stahli 23. Feb 2015 13:00

AW: MemoryLeak bei TList<IMyInterface>
 
@Sir

Ich hatte vorhin keinen roten Kasten...

Heißt das, wenn ich Interface-Parameter in einer Methode nicht benutzt wird gibt es ein MemoryLeak?
Das wäre ja eine sehr unschöne Sache.

Nach meiner derzeitigen Einschätzung dürfte das aber nicht das vorliegende Problem sein, da ich das Speicherleck vermeiden kann, indem ich die Anseisung List.Add(aInterface) auskommentiere.

Mir fällt zwar gerade ein, dass ich wohl List.Add(MyObject) hinzufüge, aber das müsste ja problemlos dennoch das Interface verwalten.
Oder wäre es besser, in einem solchen Fall explizit zu casten: List.Add(MyObject as IMyInterface)? Oder sollte man sogar unbedingt eine temporäre Interface-Variable anlagen und verwenden?


PS: Dein eben nachgeschobenes Construkt verwende ich definiv nicht. Mal sehen, genaueres dann heute Abend...

Sir Rufo 23. Feb 2015 13:09

AW: MemoryLeak bei TList<IMyInterface>
 
Es heisst ganz einfach:

Wenn ich eine Instanz erzeuge und das direkt als ein Argument/Parameter übergebe, dann springt der Referenzzähler nicht an.
Delphi-Quellcode:
IFoo = interface
  procedure Bar;
end;

procedure foo( aFoo : IFoo );
begin
  aFoo.Bar;
end;

var
  LFoo : IInterface;
  LFooObj : TFoo;

foo( TFoo.Create ); // aufpassen, hier kann es zu einem Leak kommen

LFoo := TFoo.Create;
foo( LFoo ); // alles in Butter

LFooObj := TFoo.Create;
foo( LFooObj ); // aufpassen, hier wird auch keine Referenz erhöht!

himitsu 23. Feb 2015 13:16

AW: MemoryLeak bei TList<IMyInterface>
 
Das ist dann aber ein Bug?


Hier
Delphi-Quellcode:
procedure foo( aFoo : IFoo );
muß die Referenzzählung hoch gehn

und hier
Delphi-Quellcode:
procedure foo( const aFoo : IFoo );
natürlich nicht.

Innerhalb der letzten Methode hat man dann viel Spaß, sobald der Zähler das erste Mal wieder auf 0 fällt.
Und ohne referenzzählenden Zugriff, auf den Parameter, gibt es ein schönes Speicherleck.

Sir Rufo 23. Feb 2015 13:30

AW: MemoryLeak bei TList<IMyInterface>
 
@himitsu

Stimmt ... das
Delphi-Quellcode:
const
ist der Üpeltäter
Delphi-Quellcode:
program dp_184063;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type
  IFoo = interface
    ['{FEF0782C-9F48-4060-A79D-8697F8431718}']
    procedure Bar;
  end;

  TFoo = class( TInterfacedObject, IFoo )
  private
    FName: string;
  public
    constructor Create( const Name: string );
    destructor Destroy; override;

    procedure Bar;
  end;

  { TFoo }

constructor TFoo.Create( const Name: string );
begin
  inherited Create;
  FName := Name;
  WriteLn( 'TFoo(', FName, ').Create' );
end;

destructor TFoo.Destroy;
begin
  WriteLn( 'TFoo(', FName, ').Destroy' );
  inherited;
end;

procedure TFoo.Bar;
begin
  WriteLn( 'TFoo(', FName, ').Bar' );
end;

procedure CallConstFoo( const aFoo: IFoo );
begin
  aFoo.Bar;
end;

procedure CallFoo( aFoo: IFoo );
begin
  aFoo.Bar;
end;

procedure Test;
begin
  CallConstFoo( TFoo.Create( 'ConstFoo' ) );
  CallFoo( TFoo.Create( 'Foo' ) );
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    Test;
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.
ergibt bis zum abschließenden
Delphi-Quellcode:
ReadLn
Code:
TFoo(ConstFoo).Create
TFoo(ConstFoo).Bar
TFoo(Foo).Create
TFoo(Foo).Bar
TFoo(Foo).Destroy
und somit einen MemLeak für die ConstFoo benannte Instanz

himitsu 23. Feb 2015 14:19

AW: MemoryLeak bei TList<IMyInterface>
 
Wir haben somit einen mindestens 20 Jahre alten "schweren" Fehler entdeckt. :firejump:

Mist, ich hätte noch eine Minute warten müssen, dann hätte ich die 10101 ergatterst. (jetzt muß ich noch einen Monat warten, bis zur 1010101 :stupid:)
https://quality.embarcadero.com/browse/RSP-10100

Wie sieht das beim ARC aus? Müsste ja eigentlich gleich sein.

Uwe Raabe 23. Feb 2015 14:50

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von himitsu (Beitrag 1291126)
Wir haben somit einen mindestens 20 Jahre alten "schweren" Fehler entdeckt. :firejump:

Naja, Fehler ist vielleicht etwas übertrieben. Immerhin setzt der Programmierer ja durch das
Delphi-Quellcode:
const
ganz bewusst die Referenzzählung außer Kraft. Man muss halt wissen was man tut. Wir sind hier ja schließlich nicht im Java-Forum.

Du schreibst ja auch selbst, daß der Compiler eine Warnung ausgeben soll, die man dann ja selbst zu einen Fehler aufwerten kann, wenn man das möchte. Und eine fehlende Warnung ist vielleicht unschön, aber für den Fehler ist man schon selbst verantwortlich und nicht der Compiler - der kann ja dort nun mal nicht anders. Das Konstrukt ist syntaktisch und semantisch korrekt, tut sogar das was es soll, führt nur leider zu einem Memoryleak. Das täte ein fehlendes
Delphi-Quellcode:
Free
bei jeder anderen Objektinstanz aber auch und dort gibt es auch keine Warnung vom Compiler (allerdings von anderen Tools).

himitsu 23. Feb 2015 15:04

AW: MemoryLeak bei TList<IMyInterface>
 
Der Compiler könnte eine Temp-Variable erstellen und diese an den Parameter übergeben. :stupid:

Gut, daß macht der Compiler bestimmt, aber ich wette das ist eine Objekt-Variable, die hier ja nicht referenzgezählt sind.

[edit] Dann könnte es im ARC doch funktionieren, aber dann müssten wie auch noch prüfen, ob das bei allen Objekten, auch aus Objektvariablen, bei Übergabe an Const-Interface-Parameter knallt. :shock:

Memnarch 23. Feb 2015 16:17

AW: MemoryLeak bei TList<IMyInterface>
 
Wie bereits im Ticket erwähnt, hat dies nichts mit dem direkten übergeben von erstellten Objekten zu tun. Dieses verhalten bekommt ihr bei impliziten casts von Objectinstanzen auf Interface bei Parametern.

Stevie 23. Feb 2015 19:08

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von himitsu (Beitrag 1291126)
Wir haben somit einen mindestens 20 Jahre alten "schweren" Fehler entdeckt. :firejump:

Entdeckt? Pff, der Fehler is fast so lang bekannt, wie er existiert - gratulation zum x-ten Duplicate Report diesbezüglich.

Gab erst vor nicht allzu langer Zeit dazu eine Diskussion (und Ausreden, warums nich gemacht wird)

Sehr lustig auch der "Closed" Kommentar zu dem von mir verlinkten Ticket:
"Works as expected.
Should not pass const interface parameter to non-const parameter."

What the f...?

Am besten einfach drauf sch...verzichten, dass sie es jemals fixen und hier nen upvote geben:
http://fixinsight.userecho.com/topic...e-same-object/

himitsu 23. Feb 2015 21:55

AW: MemoryLeak bei TList<IMyInterface>
 
Im neuen QC ist er noch nicht doppelt. :mrgreen:

stahli 24. Feb 2015 11:28

AW: MemoryLeak bei TList<IMyInterface>
 
generell:

Der Fehler ist ganz sicher als ein solcher zu bezeichnen.
Über das Problem wird wohl jeder stolpern, der Interfaces in Delphi benutzt. Ein logisches und zu erwartendes Verhalten ist das jedenfalls nicht.
Es ist für mich nicht nachvollziehbar, dass Emba das nicht in Ordnung bringt (ggf. mit einem Projektschalter: InterfaceMemoryLeakProblemBeibehalten = True).


mein Problem:

... konnte ich damit aber noch nicht bereinigen. Muss ich heute Abend mal weiter graben.
Ich erzeuge über eine Factory Objekte und verwalte die Schnittstellen in verschiedenen Listen. An einer Stelle stelle funktioniert das irgendwie nicht richtig (entweder gibt es MemoryLeaks oder Zugriffsverletzungen) und ich konnte den Fehler bisher trotz der oben Hinweise noch nicht finden.


eine andere Frage noch:

In den überwachten Ausdrücken kann ich ja MyObject.RefCount einsehen.
Wenn ich aber nur eine Schnittstelle IMyInterface habe geht das nicht.
Ein casten (MyInterface as TMyClass).RefCount funktioniert auch nicht.
Wie kann ich den RefCount eines Interfaces (oder des Objektes hinter einem Interface) einsehen?

himitsu 24. Feb 2015 12:32

AW: MemoryLeak bei TList<IMyInterface>
 
AS kann in den überwachten Ausdrücken nicht verwendet werden,
auch solltest du Seiteneffekte erlauben.
  • Entweder du baust dir ins Interface eine GetRefCount-Methode ein
  • oder du baust dir eine Funktion, welche das Interface als CONST entgegennimmt, RefCount zurückgibt und rufst diese Funktion in den Ausdrücken auf.

stahli 24. Feb 2015 12:52

AW: MemoryLeak bei TList<IMyInterface>
 
Ok, danke für die Idee.

Ich dachte eigentlich, dass ich mich als NixBlicker oute.
Dass die IDE das wirklich nicht anzeigt ist echt schwach.
Das braucht doch eigentlich jeder, der intensiver mit Interfaces arbeitet...

himitsu 24. Feb 2015 12:56

AW: MemoryLeak bei TList<IMyInterface>
 
"intensiv" ist gut, ich wollte eine gemeinsame Funktion (speicherverwaltung für sich gegenseitig referenzierende Interfacelisten) in einem generischen Interface+Klasse umsetzen, aber kurz vorm Ende, bin ich mal wieder an die Grenzen der Generics gestoßen. :wall:

stahli 26. Feb 2015 11:31

AW: MemoryLeak bei TList<IMyInterface>
 
Hmm, offenbar sind gegenseitige Referenzen mein Problem.

Ich habe ein MyIntf, das eine Eigenschaft IMyParentList unterstützt.
Das Interface weiß also, von welcher Liste es kontrolliert wird und kann diese über bestimmte Änderungen informieren.

Jetzt wird aber wohl die IMyParentList nicht freigegeben weil MyIntf nicht freigegeben wird und anders rum.
In der Richtung scheint das Problem zu liegen. Heute Abend geht´s dann weiter.

So wie ich das verstehe, fällt das thematisch wohl auch in diesen Bereich: http://www.delphipraxis.net/184100-weak-tlist.html


Aber mal noch 2 andere Dinge:

Warum sind denn _AddRef und _Release nicht virtuell? Dann könnte man sich mal schnell reinhängen und die Ref-Änderungen leichter nachvollziehen.

Sehr verwirrend finde ich auch das Verhalten im Constructor.

Delphi-Quellcode:
constructor TFoo.Create;
begin // RefCount = 0
  IrgendwasInZeileEins; // RefCount = 1 ... hier nur um zu zeigen, dass es nicht mit inherited zusammenhängt
  inherited; // RefCount = 1
end; // RefCount = 0

..
  FooObj := TFoo.Create; // RefCount = 0
  FooIntf := TFoo.Create; // RefCount = 1
..
Der RefCounter wird erst mal erhöht und dann wieder auf 0 reduziert.

In bestimmten Fällen scheint er aber auf 1 zu bleiben und das FooIntf hat dann RefCount = 2. Bisher habe ich nicht gefunden, wann das auftritt.
Irgendwas muss da im Contructor anders laufen (und meine Vermutung, dass ich da etwas vermurkst habe, konnte ich bisher nicht bestätigen).

himitsu 26. Feb 2015 12:11

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291604)
Hmm, offenbar sind gegenseitige Referenzen mein Problem.

http://www.delphipraxis.net/184100-weak-tlist.html usw.

Jupp, fällt in den Bereich. :stupid:

Zitat:

Warum sind denn _AddRef und _Release nicht virtuell
Das hab ich mich auch schon gefragt. :wall:

Du kannst aber (theoretisch) das Interface neu einbinden und auf die neuen/eigenen Methoden verweisen.
Früher hatte ich einfach nur selber das IInterface implementiert, aber wenn du jetzt mal in TInterfacedObject nachsiehst, was dort gemacht wird ... das will ich nicht mehr selber (nach)machen. :freak:

Der schöne Günther 26. Feb 2015 12:41

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291604)
Warum sind denn _AddRef und _Release nicht virtuell? Dann könnte man sich mal schnell reinhängen und die Ref-Änderungen leichter nachvollziehen.

Ich hab das Thema zwar nicht mitgelesen, aber das hat mich auch schon mal geärgert. Dass man die Methoden aus Performance-Gründen nicht virtuell macht kann ich verstehen, aber wie toll wäre es, sie bei
Delphi-Quellcode:
IFDEF DEBUG
doch virtuell zu haben?

Stevie 26. Feb 2015 12:58

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291604)
Sehr verwirrend finde ich auch das Verhalten im Constructor.

Delphi-Quellcode:
constructor TFoo.Create;
begin // RefCount = 0
  IrgendwasInZeileEins; // RefCount = 1 ... hier nur um zu zeigen, dass es nicht mit inherited zusammenhängt
  inherited; // RefCount = 1
end; // RefCount = 0

..
  FooObj := TFoo.Create; // RefCount = 0
  FooIntf := TFoo.Create; // RefCount = 1
..
Der RefCounter wird erst mal erhöht und dann wieder auf 0 reduziert.

Einfach mal den Source von TInterfacedObject lesen.

stahli 26. Feb 2015 13:09

AW: MemoryLeak bei TList<IMyInterface>
 
Ja, habe ich natürlich auch vor (hatte ich natürlich auch schon mal oberflächlich).

Aber egal, was dort passiert, das dürfte doch erst bei "inherited" abgearbeitet werden und nicht bei "begin"!?
Daher bin ich davon ausgegangen, dass der Linker da irgendwas tut, das man innerhalb der Klasse nicht wirklich erkennen kann.

Uwe Raabe 26. Feb 2015 13:25

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291625)
Aber egal, was dort passiert, das dürfte doch erst bei "inherited" abgearbeitet werden und nicht bei "begin"!?
Daher bin ich davon ausgegangen, dass der Linker da irgendwas tut, das man innerhalb der Klasse nicht wirklich erkennen kann.

Kann man schon erkennen, wenn man weiß, wo man suchen muss:

Zitat:

// Set an implicit refcount so that refcounting during construction won't destroy the object.
class function TInterfacedObject.NewInstance: TObject;

Uwe Raabe 26. Feb 2015 13:26

AW: MemoryLeak bei TList<IMyInterface>
 
Das Pendant dazu steht dann unter

Delphi-Quellcode:
procedure TInterfacedObject.AfterConstruction;

stahli 26. Feb 2015 18:28

AW: MemoryLeak bei TList<IMyInterface>
 
Ok, danke, so tief war ich da noch nicht eingestiegen (verstehe das auch jetzt nur ansatzweise).


Das Problem RefCounter mal 1 mal 2 konnte ich jetzt etwas eingrenzen:


Von der Factory wird nur ein Objekt erzeugt und als Interface zurück gegeben.

Wenn ich das Ergebnis einer lokalen Interfacevariable zuweise ist RefCounter 1.
Die gleiche Zuweisung zu einem privaten Feld führt zu RefCount = 2.

Ich kann mir vorstellen, dass es daran liegt, dass die Methode (aktueller Scope) auf das Feld zugreift und die Klasseninstanz als solche auch nochmal.
Ist das so oder lässt sich das anders erklären?

Delphi-Quellcode:
  TDings = class(TInterfacedObject)
  private
    fBumsList: IGuidList;
    ...
  public
    constructor Create; override;
    destructor Destroy; override;
    ...
  end;


constructor TDings.Create;
var
  tmpBumsList: IGuidList;
begin
  inherited;

  tmpBumsList := TFactory.GetNewGuidList;
  // tmpBumsList.RefCount = 1

  fBumsList := TFactory.GetNewGuidList;
  // fBumsList.RefCount = 2
end;

himitsu 26. Feb 2015 18:36

AW: MemoryLeak bei TList<IMyInterface>
 
Es kann sein, daß der Compiler die Variable tmpBumsList direkt als Result für GetNewGuidList verwendet.
Nein, das ist bestimmt so.

Gemanagete Typen als Result werden in einen Var-Parameter umgewandelt.
Aus
Delphi-Quellcode:
function GetNewGuidList: IGuidList;
macht der Compiler ein
Delphi-Quellcode:
procedure GetNewGuidList(var Result: IGuidList);
.

Da das Feld nicht direkt übergeben werden kann (bzw. er zu doof dafür ist), wird automatisch eine temporäre Variable generiert.

Der Code des Compilers sieht also so aus
Delphi-Quellcode:
constructor TDings.Create;
var
  tmpBumsList: IGuidList;
  {$REGION 'AUTOGENERATED'}
  AutogeneratedVariable1: IGuidList;
  {$ENDREGION}
begin
  {$REGION 'BEGIN'}
  tmpBumsList := nil;
  AutogeneratedVariable1 := nil;
  try
  {$ENDREGION}

  inherited Create;

  TFactory.GetNewGuidList(tmpBumsList);
  // tmpBumsList.RefCount = 1

  TFactory.GetNewGuidList(AutogeneratedVariable1);
  Self.fBumsList := AutogeneratedVariable1;
  // fBumsList.RefCount = 2

  {$REGION 'END'}
  finally
    tmpBumsList := nil;
    AutogeneratedVariable1 := nil;
  end;
  {$ENDREGION}
end;

Stevie 26. Feb 2015 18:48

AW: MemoryLeak bei TList<IMyInterface>
 
Zitat:

Zitat von stahli (Beitrag 1291655)
Ok, danke, so tief war ich da noch nicht eingestiegen (verstehe das auch jetzt nur ansatzweise).

Einfach mal mit Debug dcus durch ein TInterfacedObject.Create mit F7 steppen und schauen.

@Himi
Und wo soll das jetzt nen Memoryleak sein? Temporäre RefCounts sind doch egal.
Am Ende der Methode wird die compilergenerierte implizite Variable gecleart und alles is gut. :)

stahli 26. Feb 2015 18:54

AW: MemoryLeak bei TList<IMyInterface>
 
@himi

Einen IchVerneigeMichVorDir-Smily hat die DP ja nicht - hilfsweise dann so: :kiss:

Das klingt einleuchtend und plausibel. Aber wie bekommt man das raus?


@Stevie

Das MemoryLeak ist woanders verursacht. Mein 1:2-Problem ergab sich als Fragestellung zwischendurch bei der Fehlersuche, ist aber nicht Fehlerverursachend.

himitsu 26. Feb 2015 20:03

AW: MemoryLeak bei TList<IMyInterface>
 
Jupp, kein Speicherleck ... zwei Variablen = zwei Referenzen :D

Zitat:

Zitat von stahli (Beitrag 1291662)
Aber wie bekommt man das raus?

Das weiß man. :zwinker:

Oder man versucht rauszubekommen was man im Assembler sieht.
Aber so ist es die einzige sichere Möglichkeit, den Speicher/Referenzen auch bei Exceptions konsistent zu halten, also indem man den Speicher außenrum absichert.
Die Result-Variable wird ja bei Exceptions einfach "ignoriert" und nicht weiter behandelt.

stahli 28. Feb 2015 17:20

AW: MemoryLeak bei TList<IMyInterface>
 
Jetzt wieder zum eigentlichen Thema: gegenseitige Referenzierung IListe <-> IEintrag ...

Ein klassischer Lösungsansatz geht offenbar über TAggregatedObject.
Das Pointergeschiebe ist mir aber irgendwie suspekt (genauer gesagt verstehe ich das nicht ausreichend und erscheint mir das recht unsicher).

Mir erscheint es für meinen Anwendungsfall sinnvoller, auf die automatische Referenzzählung zu verzichten.
Diese finde ich (wenn es um Datenklassen geht) auch etwas fragwürdig.

Ein abstraktes Beispiel: Ich habe ein Spiel mit einer Straße und einem Gullydeckel. Der Gullydeckel wird gesprengt (FreeAndNil bzw. :=nil).
Wenn jetzt irgendeine Variable noch eine Instanz darauf hält, existiert der Deckel noch und die Figur kann weiter darüber laufen - tatsächlich müsste sie aber in das Loch fallen oder ein Fehler auftreten.

Da ich meine Objekte ohnehin alle selbst verwalte und dies innerhalb meines geschlossenen Projektes, kann ich mir auch die Kontrolle über meine Objekte vorbehalten. Implementation von klassenübergreifenden Funktionalitäten (als eigentlichen großen Vorteil von Interfaces) kann ich ja weiter über Interfaces realisieren.

So sollten auch gegenseitigen Referenzierungen kein Problem mehr darstellen (wenn ich das intern ordentlich verwalte - dafür gibt es ja wieder verschiedene Ansätze).

Will da jemand Veto einlegen?


Falls jemand zu dem Thema nachlesen will, hier mal meine gefundenen Links:
http://www.delphipraxis.net/331268-post6.html
http://www.delphipraxis.net/812576-post5.html
http://www.delphipraxis.net/176352-w...-compiler.html
http://www.delphipraxis.net/178822-d...verhalten.html
http://www.delphipraxis.net/177999-w...tedobject.html
http://www.delphipraxis.net/919620-post5.html <-- so sehe ich das jetzt auch
http://www.delphipraxis.net/155315-i...zzaehlung.html
http://forum.delphi-treff.de/index.p...-deaktivieren/

Stevie 28. Feb 2015 23:22

AW: MemoryLeak bei TList<IMyInterface>
 
Wie immer heißt es hier: kommt drauf an

Ich unterscheide schon seit einiger Zeit Klassen in Daten- und Serviceklassen.

Siehe dazu diesen interessanten Artikel.
Das ist, wie er dort erläutert, auch bei DI wichtig.

Und aus diesem Grunde vermeide ich es auch, in den Datenobjekten zu viel Logik unterzubringen, die möglicherweise Abhängigkeiten auf Services nach sich ziehen.

himitsu 11. Mär 2015 00:07

AW: MemoryLeak bei TList<IMyInterface>
 
Wenn ich mir die fremden Umbauten an meinem Beispielcode anseh, dann macht dort jemand scheinbar Unittests.
Kann also nicht mehr lange dauern, bis zur Problemlösung. :-D

https://quality.embarcadero.com/browse/RSP-10100


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:41 Uhr.

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