Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays (https://www.delphipraxis.net/160329-seltsames-speicherleak-problem-mit-records-verbindung-mit-arrays.html)

s.h.a.r.k 8. Mai 2011 17:58

Delphi-Version: XE

Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Nachdem wir gerade eh schon so viele schöne Record-Threads am laufen haben, habe ich mir gedacht, ich programmiere einfach mal eine Anwendung, welches sich mit Speicherleaks beschäftigt, die bei der Benutzung von Records auftreten :stupid: Hier mal ein wenig Code:
Delphi-Quellcode:
type
  TDynIntArray = array of Integer;
  TStatIntArray = array[0..1] of Integer;
var
  Tmp : TStatIntArray;
  //Tmp : TDynIntArray;
  //Tmp : TArray<Integer>;
begin
  ReportMemoryLeaksOnShutdown := True;
  try
    // Set up a array with two elements
    //SetLength(Tmp, 2); // <- Für dyn. Arrays entkommentieren!
    Tmp[0] := 10;
    Tmp[1] := 3;

    // Diese Zeile liefert kein Speicherleak
    //TValue.From<Integer>(6).ToString();

    // Egal welcher dieser Zeilen aktiviert wird -> Speicherleak.
    // Darunter findet sich eine Beispielmeldung von FastMM4.
    Writeln( TValue.From<TStatIntArray>(Tmp).ToString() );
    //Writeln( TValue.From<TDynIntArray>(Tmp).ToString() );
    //Writeln( TValue.From<TArray<Integer>>(Tmp).ToString() );

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

    5 - 12 bytes: Unknown x 1
    13 - 20 bytes: Unknown x 1
    21 - 36 bytes: TValueDataImpl x 1
    *)
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Kann mir jemand erklären, warum Delphi nicht erkennt, dass hier was selbstständig aufgeräumt werden muss?

Dieser Code (leicht gekürzt) hingegen funktioniert ohne Probleme und liefert keinerlei Speicherleak:
Delphi-Quellcode:
type
  TStatIntArray = array[0..1] of Integer;
var
  Tmp : TStatIntArray;
begin
    { ... }
    Tmp[0] := 10;
    Tmp[1] := 3;

    v := TValue.From<TStatIntArray>(Tmp);
    Writeln(v.ToString());
    { ... }
end.
Daher gehe ich mal davon aus, dass Delphi Probleme mit der Verwaltung der Anzahl der Zeiger, die auf den entsprechenden Record verweisen, hat. Oder warum gibt das sonst Probleme?

Stevie 8. Mai 2011 18:20

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Bekanntes Problem (bin gerade zu faul, den QC Eintrag herauszusuchen).
Problem ist an der Stelle, dass mit dem Rückgabeergebnis einer Funktion direkt weitergearbeitet wird.

himitsu 8. Mai 2011 18:26

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
http://qc.embarcadero.com/wc/qcmain.aspx?d=44634

und da wundert man sich, warum ich kaum noch was dort reporte ... ändert sich ja eh nix

Sobald man aber den Record etwas verrößert (neue Felder einfügt), behebt sich das Problem oftmals von selber.

Stevie 8. Mai 2011 18:33

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Ah, das wars. Gemanagte Datentypen in einem Record und der als Funktionsergebnis.
Ergebnis der Funktion in einer Variable speichern und damit weitermachen behebt das Problem.

himitsu 8. Mai 2011 18:57

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von Stevie (Beitrag 1099592)
Ah, das wars. Gemanagte Datentypen in einem Record und der als Funktionsergebnis.

Eigentlich passiert es überall, aber bei ungemanagten Typen fällt es nicht auf.

USchuster 8. Mai 2011 19:09

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von Stevie (Beitrag 1099592)
Ah, das wars.

Nein, denn QC 44634 wurde in XE offenbar durch den Fix für QC 77903 behoben und in einigen Tagen wird QC den Status sicher entsprechend anzeigen.

himitsu 8. Mai 2011 19:12

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Nja, auch nur bedingt besser ... also daß man sich Bugfixes immer kaufen muß.

Stevie 8. Mai 2011 19:46

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von USchuster (Beitrag 1099598)
Zitat:

Zitat von Stevie (Beitrag 1099592)
Ah, das wars.

Nein, denn QC 44634 wurde in XE offenbar durch den Fix für QC 77903 behoben und in einigen Tagen wird QC den Status sicher entsprechend anzeigen.

Tja, kann ich nur sagen, dann haben sie es nicht richtig gefixt.

Boom:
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

type
  TRecord2 = record
    FIntf: IInterface;
  end;

  TRecord1 = record
    FRecord2: TRecord2;
    function Foo: string;
  end;

function Get: TRecord1;
begin
  Result.FRecord2.FIntf := TInterfacedObject.Create;
end;

function TRecord1.Foo: string;
begin
  Result := '';
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Get.Foo;
end.
Genau das passiert nämlich im Fall von TValue. Dort gibts intern das Feld FData vom Typ TValueData, worin wiederum eine Interface Referenz (IValueData) gespeichert wird. Daher auch der Memleak des TValueDataImpl Objektes.

USchuster 8. Mai 2011 20:30

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von Stevie (Beitrag 1099602)
Zitat:

Zitat von USchuster (Beitrag 1099598)
Zitat:

Zitat von Stevie (Beitrag 1099592)
Ah, das wars.

Nein, denn QC 44634 wurde in XE offenbar durch den Fix für QC 77903 behoben und in einigen Tagen wird QC den Status sicher entsprechend anzeigen.

Tja, kann ich nur sagen, dann haben sie es nicht richtig gefixt.

"Es" kann auch nicht gefixed werden, sondern nur konkrete Probleme in Form von Testfällen mit vollständigem Quellcode. QC 44634 ist gefixed, jedoch QC 75036 ist es nicht. Letzteres entspricht wohl dem Problem hier inkl. Deinem Beispiel. Wenn TRecord1 in einer Variable gespeichert wird

Delphi-Quellcode:
var
  R: TRecord1;
begin
  ReportMemoryLeaksOnShutdown := True;
  R := Get;
  R.Foo;
end.
, wie in QC 75036 oder Armins gekürztem Beispiel, dann gibt es kein Memoryleak. Damit Embarcadero es "diesmal" "richtiger" macht, schicke ich denen Armins gekürztes Beispiel in der kapputten Fassung.

Stevie 8. Mai 2011 21:19

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von USchuster (Beitrag 1099607)
"Es" kann auch nicht gefixed werden, sondern nur konkrete Probleme in Form von Testfällen mit vollständigem Quellcode.

Wenn man die Bugfixes nicht jedes Jahr wieder mit teuerem Geld bezahlen müsste, wäre die Bereitschaft, selber mehr Zeit in Fehlerdiagnosen zu stecken, sicher größer. :roll:

s.h.a.r.k 8. Mai 2011 22:01

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
AHHHH... :wall: Sowas ist doch Käse. Vor allem, weil es diesen Fehler wohl schon sehr, sehr lange gibt und er immer noch nicht gefixt wurde :roll:

Naja, das ganze klagen hilft leider nicht sehr viel, da es am Status im Moment nur sehr wenig bis gar nichts ändern wird. Zum Glück kann ich daher aber meinen Code einfach belassen, man muss ihn halt einfach nur anders nutzen.

Herzlichen Dank für euer Know How! Ich seh schon, ich sollte auch mal grob über das QC drüber schauen -- aber da steht eben auch nicht gerade wenig, was dann in einem ziemlichen Aufwand ausufern könnte...

-- Edit: Wow... Es wird echt immer besser :mrgreen:
Delphi-Quellcode:
type
TApDynamicArray<T> = record
public type
  TApArrayToStringFunc = reference to function(Value: T): String;
public
  function ToString(const ToStrFunc: TApArrayToStringFunc): String;
end;

function TApDynamicArray<T>.ToString(const ToStrFunc: TApArrayToStringFunc): String;
begin
end;


procedure PrintIntegerArray(A: TApDynamicArray<Integer>);
begin
  Writeln( A.ToString(IntToStr) );
end;

var
  Tmp : TApDynamicArray<Integer>;
begin
  ReportMemoryLeaksOnShutdown := True;
  //Writeln( Tmp.ToString(IntToStr) );
  PrintIntegerArray(Tmp)
end.
... liefert in der aktuell gezeigten Version kein Speicherleak. Wenn ihr allerdings PrintIntegerArray() entfernt und das Writeln() aktiviert, dann kommt ein nettes Speicherleak zustande. Da fällt mir nur noch folgendes ein: WTF :roll:
Code:
---------------------------
Project1.exe: Memory Leak Detected
---------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):

13 - 20 bytes: Project1$1697$ActRec x 1
Entfernt man das reference to beim Typen TApArrayToStringFunc, dann funktionieren beide Versionen. Ist doch alles echt so super... Jetzt fang ich dann auch noch an, jeden scheiß zu überladen und auszubauen und hoffe, dass der Compiler alles mal in 10 Jahren auf die Reihe bring.

Stevie 9. Mai 2011 06:27

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Das hat was mit einer anonymen Methode in der main der dpr zu tun.

Boom:
Delphi-Quellcode:
procedure Foo(f: TFunc<Integer, string>);
begin
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Foo(IntToStr);
end.
Seit ich das weiß, mach ich keine Testanwendungen mehr als Consoleprojekt (zumindest nicht die, wo ich regen Gebrauch von delegates mache)

s.h.a.r.k 9. Mai 2011 13:43

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von Stevie (Beitrag 1099626)
Das hat was mit einer anonymen Methode in der main der dpr zu tun.
[...]
Seit ich das weiß, mach ich keine Testanwendungen mehr als Consoleprojekt (zumindest nicht die, wo ich regen Gebrauch von delegates mache)

Du machst Witze, oder? :lol:

himitsu 9. Mai 2011 14:03

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Ich mach wegen sowas auch keinen Testcode mehr direkt in die DPR ... zumindestens nicht ins
Delphi-Quellcode:
begin ... end.
davon,
also mindestens in eine Procedur ausgelagert und auf globale Variablen sollte man bei sowas auch verzichten.

s.h.a.r.k 9. Mai 2011 14:40

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Bin auch eher durch Zufall auf das Problem gestoßen, da ich mir eigentlich immer eine Testklasse anlege, um den Code innerhalb der Main-Methode einigermaßen clean und übersichtlich zu halten. Wollte dann schnell was testen und *BOOM*... Hab mich gerade mal wieder ein wenig verschiedene Blogs gekämpft und es ist eigentlich echt frustrierend, wie viele Feinheiten man wissen muss/sollte, sodass man nicht an jeder zweiten Ecke einen Memoryleak erhält. Gleiches trifft dann ja leider auch auf den User des Codes zu, der den Code dann später mal verwendet -- ausgehend davon, dass man den Code nicht nur für sich selber schreibt.

himitsu 9. Mai 2011 14:49

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Mein letztes Speicherproblem mit diesen Records, Generics und Co. war ja eher, daß Delphi mal zuviel freigibt ... so zur abwechslung :lol:
(will etwas doppelt freigeben)

BUG 9. Mai 2011 14:56

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von Stevie (Beitrag 1099626)
Das hat was mit einer anonymen Methode in der main der dpr zu tun.

Boom:
Delphi-Quellcode:
procedure Foo(f: TFunc<Integer, string>);
begin
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Foo(IntToStr);
end.

Nur mal so nebenbei, welche Funktion ist hier den anonym :gruebel:

s.h.a.r.k 9. Mai 2011 15:39

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
In dem Fall ist es wahrlich keine anonyme Methode. Das Problem hat eher was mit dem reference to zu tun:
Delphi-Quellcode:
type TFunc = reference to function...

Stevie 9. Mai 2011 15:58

AW: Seltsames Speicherleak-Problem mit Records in Verbindung mit Arrays
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1099723)
Du machst Witze, oder? :lol:

Nein.
Zitat:

Zitat von BUG (Beitrag 1099744)
Nur mal so nebenbei, welche Funktion ist hier den anonym :gruebel:

Ja ich weiß, method reference wäre politisch korrekt gewesen. 8-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:26 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