Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Memleak, vermutlich bei VarArray/PSafeArray Nutzung (https://www.delphipraxis.net/65170-memleak-vermutlich-bei-vararray-psafearray-nutzung.html)

DarKlajid 13. Mär 2006 10:48


Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Mahlzeit.

Bitte nicht schlagen: Ich bin eigentlich ein Jünger der GC Sprachen (.Net/Java Background) und falle hier gerade gehörig auf die Nase. Problem:

Ein Programm nutzt COM als Interface zu .Net Services und braucht dafür u.a. PSafeArrays. Die bisher simpelste Methode ein solches zu bauen schien mir ein VariantArray zu casten. D.h. ich habe eine Funktion die wie folgt aussieht:

Delphi-Quellcode:
procedure TMyType.CopyForms(var p_Param1 : IMyComType; var p_Param2 : IMyComType2; var p_Param3 : TStringList);
var
  vFormNames : Variant;
  iNameIndex : integer;
begin
  vFormNames := VarArrayCreate([0, p_Param3.Count - 1], varOleStr);

  try // try-finally
    for iNameIndex := 0 to p_Param3.Count - 1 do
    begin
      vFormNames[iNameIndex] := p_Param3[iNameIndex];
    end;

    p_Param1.CopyForms(p_Param2, PSafeArray(TVarData(vFormNames).VArray), False);
  finally
    Finalize(vFormNames);
    vFormNames := Unassigned;
  end;
end;
Abgesehen davon, dass der Code sicherlich weit davon entfernt ist, optimiert zu sein (Eine Liste durchlaufen um ein Array zu füllen? Sieht seltsam aus..):
MemProof sagt, dass in der Zuweisung eines Strings zum VarArray (in der for-loop) bei jedem Aufruf ein String leaked.. Zumindest lese ich das aus der Ausgabe - auch dort ist meine Erfahrung eingeschränkt.
Nachdem ich aber schon eine ganze Weile rumstocher und bisher trotz Google oder der Forensuche hier nichts erfahren hab: Mag mich jemand auf meinen Fehler hinweisen? Jede Hilfe wäre wirklich klasse..

Danke,
Ben

shmia 13. Mär 2006 12:28

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Delphi-Quellcode:
// falsch:
// Interface-Zeiger werden als var-Parameter übergeben
procedure TMyType.CopyForms(var p_Param1 : IMyComType; var p_Param2 : IMyComType2; var p_Param3 : TStringList);

// richtig:
// Interface-Zeiger werden by Value übergeben
// auch Delphi-Objekte werden by Value übergeben
procedure TMyType.CopyForms(p_Param1 : IMyComType; p_Param2 : IMyComType2; p_Param3 : TStringList);

DarKlajid 13. Mär 2006 13:04

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Zitat:

Zitat von shmia
Delphi-Quellcode:
// falsch:
// Interface-Zeiger werden als var-Parameter übergeben
procedure TMyType.CopyForms(var p_Param1 : IMyComType; var p_Param2 : IMyComType2; var p_Param3 : TStringList);

// richtig:
// Interface-Zeiger werden by Value übergeben
// auch Delphi-Objekte werden by Value übergeben
procedure TMyType.CopyForms(p_Param1 : IMyComType; p_Param2 : IMyComType2; p_Param3 : TStringList);

Danke für die (knappe?) Antwort. Leider ändert das nichts an meinem Verhalten/Problem.
Will sagen:

- Funktioniert wie gehabt
- Leakt wie gehabt (laut MemProof halt genau in dieser Funktion und zwar eine Unmenge an Strings..)

Ich hab die Funktion "komprimiert" in:

Delphi-Quellcode:
procedure TMyType.CopyForms(p_Param1 : IMyComType; p_Param2 : IMyComType2; p_Param3 : TStringList);
var
  vFormNames : Variant;
begin
  try // try-finally
    vFormNames := VarArrayFromStrings(p_Param3);

    p_Param1.CopyForms(p_Param2, PSafeArray(TVarData(vFormNames).VArray), False);
  finally
    Finalize(vFormNames);
    vFormNames := Unassigned;
  end;
end;
Vorher war es die Zeile:
Delphi-Quellcode:
FormNames[iNameIndex] := p_Param3[iNameIndex];
Jetzt ist es:
Delphi-Quellcode:
vFormNames := VarArrayFromStrings(p_Param3);
Der Stacktrace des Leaks ist über diesen Zeilen:
Zitat:

system.pas - WStrFromPWCharLen
variants.pas - VarFromWStr
meineUnit - DieZeileVonOben
Danke im voraus für jede Hilfe,
Ben

shmia 13. Mär 2006 13:28

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Dann musst du den Fehler Schritt für Schritt einkreisen.
Ich würde nur mal VarArrayFromStrings für sich alleine testen.
die Funktion sieht bei dir wohl auch so aus:
Delphi-Quellcode:
function VarArrayFromStrings(list:TStrings): Variant;
var
  iNameIndex : integer;
begin
  Result := VarArrayCreate([0, list.Count - 1], varOleStr);

  for iNameIndex := 0 to list.Count - 1 do
  begin
    Result[iNameIndex] := list[iNameIndex];
  end;
end;
Ich habe diese Funktion mit MemCheck 2.73 und FastMM4 überprüft -> kein Leak.
Versuch's mal mit MemProof, könnte ja auch ein Problem von MemProof sein.

DarKlajid 13. Mär 2006 15:18

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Ich habe gerade mit MemCheck nach eben diesem Leak gesucht und erhalte folgende Ausgabe am Ende des Programms:

MemCheck version 2.73

Total leak: 0 bytes


*** MEMCHK: Blocks STILL allocated ***

*** MEMCHK: End of allocated blocks ***


*** MEMCHK: Chronological leak information ***


*** MEMCHK: End of chronological leak information ***


*** MEMCHK: Blocks written to after destruction ***

Bad blocks count: 0


*** MEMCHK: End of blocks written to after destruction ***

Nun ja.. Schön wär's ja.. FastMM will bei mir gar keine Ausgabe machen, auch im FullDebugMode nicht.. Da ist wohl noch etwas basteln angesagt. Leider ist die Dokumentation ja recht dürftig..

DarKlajid 13. Mär 2006 17:34

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Sorry, ich will das Thema nicht pushen. Vielleicht hat aber jemand ein paar Ratschläge zu den Resultaten bisher..

Mit der memcheck Unit bekomme ich am Ende das Resultat "kein Leak gefunden". Meine Applikation startet mit 80 MB Speicherverbrauch (Overhead der externen Dependencies, nicht meine Schuld) und hat nach etwas Arbeit locker 400-500 MB im Taskmanager für sich veranschlagt. Die Daten bekomme ich schubweise und nach jeder Bearbeitung (bestehend aus einigen COM-Aufrufen hauptsächlich) ist der Speicherverbrauch signifikant höher.
FastMM bekomme ich nicht dazu, mir Hinweise/Logs in irgendeiner Art zu generieren. Ich erhalte keine Fehler mit FastMM als erster Unit, aber Leaks oder irgendwas als Report gibt es halt nicht. Die Include-Datei ist jedoch imo korrekt angepasst.
MemProof meldet mir Leaks, allerdings "nur" SysStrings. Ich denke nicht, dass ich mit Dutzenden/Hunderten von Strings (Länge entweder exakt 6 Zeichen oder grob 20, das Problem mit den VarArrays tritt an zwei Stellen auf) auf Dutzende/Hunderte von MBs an Speicherverbrauch komme? Der Stack zu den Leaks ist wie o.a. vor meiner Funktion:

System.pas:WStrFromPWCharLen
Variants.pas:VarFromWStr
... mein Kram ...

Wenn ich mir den Inhalt der Strings/Leaks anschaue, dann erkenne ich Daten, die ich als PSafeArray an COM übergeben musste. Dafür habe ich VarArrayCreate() oder VarArrayFromStrings() verwendet und das Ergebnis in ein PSafeArray gecastet. Ich will nun keineswegs Fehler auf meiner Seite oder sogar auf der COM-Seite (ein .Net Framework) ausschliessen. Ich werde sicherlich etwas sehr dummes machen - nur bin ich langsam am Ende mit Ideen.
Inzwischen falle ich schon zu einem try/finally/FreeAndNil oder Finalize um fast jedes Statement zurück.

Gibt es bekannte dumme Dinge die bei Varianten/VarArrays/PSafeArrays passieren können?

Danke für jeden Hinweis,
Ben

Neuromancer 13. Mär 2006 19:38

Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
 
Hallo DarKlajid,

versuche mal, das PSafeArray mit "SafeArrayDestroy" nach Gebrauch zu zerstören. Zu finden in der Unit ActiveX.

Bitte frag mich nicht, warum man ein COM-Array zerstören/freigeben muss. COM sollte sich doch eigentlich aufgrund seiner Garbage Collection selbst im Zaum halten.

Siehe dazu auch diesen Thread.

Gruß


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