![]() |
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:
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..):
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; 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 |
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); |
Re: Memleak, vermutlich bei VarArray/PSafeArray Nutzung
Zitat:
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:
Vorher war es die Zeile:
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;
Delphi-Quellcode:
Jetzt ist es:
FormNames[iNameIndex] := p_Param3[iNameIndex];
Delphi-Quellcode:
Der Stacktrace des Leaks ist über diesen Zeilen:
vFormNames := VarArrayFromStrings(p_Param3);
Zitat:
Ben |
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:
Ich habe diese Funktion mit MemCheck 2.73 und FastMM4 überprüft -> kein Leak.
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; Versuch's mal mit MemProof, könnte ja auch ein Problem von MemProof sein. |
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.. |
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 |
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 ![]() Gruß |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:31 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 by Thomas Breitkreuz