Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Leak verzweifelt gesucht (https://www.delphipraxis.net/80200-leak-verzweifelt-gesucht.html)

DGL-luke 4. Nov 2006 14:57


Leak verzweifelt gesucht
 
Ich hab hier ein ziemlich konfuses Problem.

Wenn ich - bei absolut unverändertem Programmtext - die Compilier-Optimierung einschalte, passiert folgendes:

- Ein IsWindow-Aufruf, der ein meistens valides Window-Handle eines fremden Prozesses (nicht wirklch fremd, wird per shellexecute gestartet) bekommt, gibt immer false zurück -> Der Prozess, zu dem das Fenster gehört wird nicht geschlossen, da ich ja meine, er exisitiert nicht mehr
- Es gibt keine Memleaks

Wenn die Optimierung aus ist, folgendes:

- IsWindow wertet richtig aus, Anwendung wird geschlossen
- FastMM meldet "3x Unknown" als Memleaks

Ich hab jetzt einfach mal {$O-}/{$O+} um die Prozedur gelegt, in der der IsWindow-Aufruf stattfindet und die Optimierung global eingeschaltet.

Dann passiert meist letzteres - manchmal bleiben aber die Leaks aus...

Wo die Leaks jetzt genau sind, hab ich keine Ahnung - der Leakreport spricht immer von zwei Prozeduren, in denen habe ich aber nur jeweils einen Record, den Delphi von sich aus alloziieren und freigeben sollte...

Was mach ich jetzt? Die zwei Prozeduren poste ich gerne, aber ich glaub nicht, dass es was bringt.

EDIT: Es spielt bei dem ganzen noch ein solchermaßen erzeugtes Message-Only-Window mit:

Delphi-Quellcode:
  //create our own message window
  //Wnd := TWinControl.CreateParented(HWND_MESSAGE);
  Wnd := TWinControl.Create(nil);
  Wnd.ParentWindow := HWND_MESSAGE;
  Wnd.WindowProc := OnMessage;
Nur zur vollständigkeit...

EDIT: upsala... Da wurde aus "Compiler-Optimierung" "Kompilierung" :oops:

Muetze1 4. Nov 2006 15:36

Re: Leak verzweifelt gesucht
 
Bitte ersetze "Kompilierung" mit "Optimierung" in deinem Text, sonst ist das mehr als schwer verständlich beim ersten Lesen.

DGL-luke 4. Nov 2006 15:55

Re: Leak verzweifelt gesucht
 
Danke für Ihren Hinweis wir werden sofort eine neue Kasse eröffnen.

EDIT: :wall:

Das FastMM-Stacktrace hat mir die Zeilennummern gezeigt. Und dank eines freundlichen #delphi.de-quakenet-users hab ich das dann auch gefunden ^^

_frank_ 4. Nov 2006 17:22

Re: Leak verzweifelt gesucht
 
und woran lags?
das mit den records kommt mir bekannt vor...hatte ein ähnliches Problem mit records.

in etwa folgendes konstrukt:

Delphi-Quellcode:
TRec = record
...
end;
PRec = ^TRec;

var pr:PRec;
new(pr);
//werte des recs per pr^.feld setzen
someTreenode.data:=pr;

//treeview1Deletion:
if assigned(node.data) then
begin
  dispose(node.data);
  node.data:=nil;
end;
lt. FastMM immer unknown mem-leaks (anzahl der records). Ich hab das record durch eine Klasse ersetzt und schon gabs keine leaks mehr...warum das so ist, hab ich nicht rausfinden können...

Gruß Frank

Muetze1 4. Nov 2006 18:57

Re: Leak verzweifelt gesucht
 
Zitat:

Zitat von _frank_
in etwa folgendes konstrukt:

Delphi-Quellcode:
TRec = record
...
end;
PRec = ^TRec;

var pr:PRec;
new(pr);
//werte des recs per pr^.feld setzen
someTreenode.data:=pr;

//treeview1Deletion:
if assigned(node.data) then
begin
  dispose(node.data);
  node.data:=nil;
end;
lt. FastMM immer unknown mem-leaks (anzahl der records). Ich hab das record durch eine Klasse ersetzt und schon gabs keine leaks mehr...warum das so ist, hab ich nicht rausfinden können...

Ist einfach zu beantworten: Dispose() will den Typ haben, damit er weiss wieviel er freigeben muss. Wenn du ihm einen Pointer gibst, dann weiss er nicht wie gross der Speicherbereich ist, den er freigeben muss. Daher darfst du ihm nicht den allgemeinen Typ von Node.Data übergeben sondern den richtigen Typ deines Records.

DGL-luke 4. Nov 2006 19:22

Re: Leak verzweifelt gesucht
 
Nein. Ich hatte vor dem korrekt getypeten (*g*) Dispose-Aufruf in einigen subversiven if-Verästelungen diverse "Exit;"s drin...

Zacherl 4. Nov 2006 20:03

Re: Leak verzweifelt gesucht
 
Um jetzt nicht einen neuen Thread aufzumachen: Ich habe ein ähnliches Problem ... warum kommt es hier zu MemoryLeaks:

Delphi-Quellcode:
procedure TMainForm.ListCategories;

procedure AddChilds(Parent: PVirtualNode; Items: array of integer);
var
  i: integer;
  Data: PCategoryData;
begin
  for i := 0 to length(Items) -1 do
  begin
    Data := Categories.GetNodeData(Categories.AddChild(Parent));
    Data.Caption := Cats[Items[i]].Caption;
    Data.Hint := Cats[Items[i]].Hint;
    Data.ImageIndex := Items[i];
  end;
end;

function AddParent(ID: integer): PVirtualNode;
var
  Data: PCategoryData;
begin
  Result := Categories.AddChild(nil);
  Data := Categories.GetNodeData(Result);
  Data.Caption := Cats[ID].Caption;
  Data.Hint := Cats[ID].Hint;
  Data.ImageIndex := ID;
  Data.IsParent := true;
end;

begin
  Categories.Clear;
  Categories.BeginUpdate;
  try
    //Client
    AddChilds(AddParent(0), [1, 2, 3]);
    //Information
    AddChilds(AddParent(4), [5, 6, 7, 8, 9, 10, 11]);
    //Administration
    AddChilds(AddParent(12), [13, 14, 15, 16, 17, 18]);
    //Shell
    AddChilds(AddParent(19), [20, 21]);
    //Sonstiges
    AddChilds(AddParent(22), [23, 24, 25, 26, 27, 28, 29, 30, 31]);
    //Spionage
    AddChilds(AddParent(32), [33, 34, 35, 36, 37]);
    //Manager
    AddChilds(AddParent(38), [39, 40, 41, 42, 43, 44]);

    //Plugins
    PluginNode := AddParent(45);
    //Server erstellen
    AddParent(46);
  finally
    Categories.EndUpdate;
  end;
end;
Delphi-Quellcode:
type
  PCategoryData = ^TCategoryData;
  TCategoryData = record
    Caption: string;
    Hint: string;
    ImageIndex: integer;
    IsParent: boolean;
  end;

type
  TCatData = record
    Caption: string;
    Hint: string;
  end;

var
  Cats: array of TCatData;
Cats wird aus einer INI Datei dynamisch geladen. Dabei sind die Items immer mit Zahlen belegt (es ist eine durchgehende Zahlenreihe von 0 .. 46)

Delphi-Quellcode:
Ini.ReadSection('Categories', Items);
SetLength(Cats, Items.Count);
for i := 0 to Items.Count -1 do
begin
  try
    Cats[StrToInt(Items[i])].Caption := Ini.ReadString('Categories', Items[i], '');
    Cats[StrToInt(Items[i])].Hint := Ini.ReadString('CatHints', IntToStr(i), '');
  except

  end;
end;
Die Freigabe sieht so aus:

Delphi-Quellcode:
procedure TMainForm.CategoriesFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  NodeArray: PCategoryData;
begin
  NodeArray := Sender.GetNodeData(Node);
  Finalize(NodeArray^);
end;
Florian

_frank_ 4. Nov 2006 21:32

Re: Leak verzweifelt gesucht
 
Zitat:

Zitat von Muetze1
Ist einfach zu beantworten: Dispose() will den Typ haben, damit er weiss wieviel er freigeben muss. Wenn du ihm einen Pointer gibst, dann weiss er nicht wie gross der Speicherbereich ist, den er freigeben muss. Daher darfst du ihm nicht den allgemeinen Typ von Node.Data übergeben sondern den richtigen Typ deines Records.

also hätte ich Dispose(PDataRec(node.data)) schreiben müssen?

Gruß Frank

DGL-luke 4. Nov 2006 21:42

Re: Leak verzweifelt gesucht
 
Ja, so klappts zumindest bei mir^^

Flocke 5. Nov 2006 10:31

Re: Leak verzweifelt gesucht
 
Zitat:

Zitat von Muetze1
Ist einfach zu beantworten: Dispose() will den Typ haben, damit er weiss wieviel er freigeben muss. Wenn du ihm einen Pointer gibst, dann weiss er nicht wie gross der Speicherbereich ist, den er freigeben muss. Daher darfst du ihm nicht den allgemeinen Typ von Node.Data übergeben sondern den richtigen Typ deines Records.

Das ist so nicht ganz richtig! Dispose benötigt nicht die Größe des Speichers, die ist dem MM bekannt. Was ohne den korrekten Typen nicht klappt ist die Finalisierung des Records, also die Freigabe von Strings und Interfaces.


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