Memory Leak: Ursache finden
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo.
Bei der Suche nach der Ursache für einen kleinen Memory-Leak, wäre ich sehr dankbar für jedwede Hilfe. Nachdem ich mit "ReportMemoryLeaksOnShutDown := True;" die Nachricht (UexpectedMemoryLeak.jpg) über einen Memory-Leak erhalten habe, aber die Ursache nicht finden konnte, habe ich MadExcept mal ausprobiert. Wie erwartet, gibt es auch einen Leak-Report (LeakReport.jpg) aus dem ich leider auch nicht schlau werde. Wenn ich in diesem Leak-Report auf die im Bild hervorgehobene Zeile im CallStack Doppelklicke, komme ich im meinem Source-Code auf diese Zeile:
Delphi-Quellcode:
Das kann aber doch nicht die Ursache für den Mem-Leak sein, oder?
setlength( fHfgkFarbe, fAnzFarben );
Jemand eine Idee, was man man aus dem MadExcept noch weiter auslesen kann, um die Urasche für den Memory-Leak auf die Spur zu kommen? Vielen Dank Jazzamn |
AW: Memory Leak: Ursache finden
Kann durchaus möglich sein; zb. wenn der Speicher für den Datentyp dieses Arrays dynamisch alloziert wird (wenn es sich zb. dabei um eine Klasse handelt)
|
AW: Memory Leak: Ursache finden
Hallo.
Vielen Dank - aber das kann ich ausschließen: Bei
Delphi-Quellcode:
wird die Länge eines Array of Integer mittles einfachem Integer (fAnzFarben) bestimmt.
setlength( fHfgkFarbe, fAnzFarben );
Steht in ähnlicher Form öfters im Source -- schließe ich somit als Verdächtigen aus. Gruß Jazzman |
AW: Memory Leak: Ursache finden
Inhaltlich kann ich nicht helfen.
Evtl. könntest Du die Trial von EurekaLog versuchen. Vielleicht hilft die ja noch genauer? |
AW: Memory Leak: Ursache finden
Man kann zuerst einmal auch manuell den Code durchscannen, sofern es sich noch um kein allzu umfangreiches Projekt handelt.
Such einfach mal nach ".Create" und "GetMem"/"New" o.Ä. Überprüfe anschließend, ob letzendlich alles allozierte auch zu 100% freigegeben wird. |
AW: Memory Leak: Ursache finden
Zitat:
|
AW: Memory Leak: Ursache finden
Ein kleiner Tipp: durchsuche den gesamten Sourcecode nach "
Delphi-Quellcode:
"; wenn irgendwo der Zusatz "
destructor Destroy;
Delphi-Quellcode:
" fehlt, dann ist das ein potentielles Speicherleck.
override;
Zusätzlich kann man noch nach "destructor T" suchen und prüfen ob in jedem Destruktor auch das
Delphi-Quellcode:
aufgerufen wurde.
inherrited
|
AW: Memory Leak: Ursache finden
Zitat:
Ich dachte schon, dass muß es sein... Dennoch ein guter Tipp! Zitat:
Zitat:
Es sind nicht allzu viele Klassen und Units -- vielleicht mal eine kleine Pause -- und dann mit Kaffee... Vielen Dank euch allen! Jazzman |
AW: Memory Leak: Ursache finden
Versuch mal im destructor der Klasse ein
Delphi-Quellcode:
SetLength(fHfgkFarbe, 0)
|
AW: Memory Leak: Ursache finden
Zitat:
Delphi-Quellcode:
Danke!
destructor TPaletto.Destroy;
begin inherited Destroy; SetLength(fHfgkFarbe, 0); end; |
AW: Memory Leak: Ursache finden
Zitat:
Grüße Klaus |
AW: Memory Leak: Ursache finden
Und so?
Delphi-Quellcode:
destructor TPaletto.Destroy;
begin SetLength(fHfgkFarbe, 0); fHfgkFarbe := nil; inherited Destroy; end; |
AW: Memory Leak: Ursache finden
Ein Array (dynamisch oder statisch) muss nicht freigeben werden. Das ist also mal nicht der Grund.
Delphi-Quellcode:
(ganz alleine für sich) ist auch eher ein Hinweis auf einen mit
Unknown
Delphi-Quellcode:
/
GetMem
Delphi-Quellcode:
allozierten Speicher-Bereich.
AllocMem
Sourcen möchtest du aber wohl hier nicht reinstellen? Dann wird es schwierig, denn so ist das ein Blindflug |
AW: Memory Leak: Ursache finden
Zitat:
Zitat:
Delphi-Quellcode:
/
GetMem
Delphi-Quellcode:
nutze ich nicht.
AllocMem
Sourcen wären im Prinzip überhaupt kein Problem -- aber es ist doch einiges an Code, und das wäre wirklich nicht ok, euch meinen Fehler im meinem Code suchen zu lassen. Sehr lieb! Ich werde morgen einfach mal eine große Auskommentierungsaktion starten und mal systematisch rang gehen. Ich bin nur ein wenig enttäuscht von MadExcept, so dass es mir wirklich gar kein Hinweis geben konnte. Ist technisch aber sicher auch nicht ganz einfach. Vielen Dank an alle - super Truppe :thumb: Gruß Jazzman |
AW: Memory Leak: Ursache finden
StrNew(), ReallocMem() ???
Ist dein Project irgendwie FPC portable? Hier ist FPC Meilen vorraus mit deren HeapTracing. Hier kann man fast ganz exakt festsetellen, wo die MemLeaks "offen" bleiben und deren Ursache ergründen. Benutzt du noch eine Ansi-Delphi? Dann könnte die MemCheck.pas genauere Infos geben.. |
AW: Memory Leak: Ursache finden
Gibst Du das TPaletto Objekt denn überhaupt frei?
|
AW: Memory Leak: Ursache finden
Zitat:
|
AW: Memory Leak: Ursache finden
Problem gelöst! :-D
Wie schon alle Tools (und auch eure Hinweise) daraufhin deuteten, hing der Memory Leak mit dem Array of Integer zusammen:
Delphi-Quellcode:
Das Array wurde anschließend überhaupt nicht benutzt (stammt noch aus einer vorherigen Version), und genau diese Zeile sorgte für den Memory-Leak. Eine Recherche in einschlägigen Foren brachte dann auch den Hinweis, dass ein FillChar zum Initialisieren von Arrays nur mit Vorsicht zu benutzen ist.
FillChar( fHfgkFarbe, SizeOf( fHfgkFarbe ), 0);
Wenn ich nun das Array manuell mit Nullen initialisiere ist alles ok. Wäre ja schon schön, wenn man eine "sichere" Methode hätte, Arrays mit Nullen zu füllen, wenn man schon FillChar nur unter bestimmten Umständen nutzen kann. Aber das Problem ist gelöst, und ich danke allen Helfern! Gruß Jazzman |
AW: Memory Leak: Ursache finden
Schön dass Du es gefunden hast. Initialierung bei einem dynamischen Array of integer wäre ja wohl eher:
Delphi-Quellcode:
FillChar( fHfgkFarbe, SizeOf(Integer) * Length(fHfgkFarbe), 0);
|
AW: Memory Leak: Ursache finden
Variablen vom Typ eines dynamischen Arrays sind Zeiger auf den Speicher in dem die Array-Elemente liegen.
Delphi-Quellcode:
Das ist falsch, so wird der Zeiger selbst überschrieben, nicht der Inhalt des Arrays.
FillChar(fHfgkFarbe, {...}
Richtig so:
Delphi-Quellcode:
if Length(fHfgkFarbe) > 0 then
FillChar(fHfgkFarbe[0], SizeOf(fHfgkFarbe[0]) * Length(fHfgkFarbe), 0); |
AW: Memory Leak: Ursache finden
Zitat:
Man kann z.B. dynamischee Arrays direkt in der Anwendung, der "Businesslogik", benützen. Oder man kapselt das Array innerhalb einer Klasse und lässt nur einen kontrollierten Zugriff über die Methoden der Klasse zu. Insbeondere sollte man Resourcen (Speicher ist auch eine Resource) immer unter die Kontrolle einer Klasse stellen. Das heisst dann konkret, dass AllocMem und FreeMem nur im geschützten Kontext einer Klasse aufgerufen werden. Dann testet man diese Klasse in einer isolierten Umgebung (aka Testprogramm) und kann so sicherstellen, dass die Klasse in sich keine Speicher- oder Resourcenlecks hat. Findet man später in der Anwendung ein Speicherleck ist die Wahrscheinlichkeit höher, dass man den Klassennamen angezeigt bekommt und so gezielt suchen kann. Manchmal bekommt man nur allgemeine Klassennamen gemeldet (z.B. TStringList x 14), dann kann man auch von TStringList abgeleitete Klassen einsetzen. Kleines Beispiel dazu:
Delphi-Quellcode:
So schlägt man zwei Fliegen mit einer Klappe.
// Klasse zum Laden von Daten aus einer Datei
// wird zum Datenimport verwendet // die Datei darf nicht leer sein TImportStringList = class(TStringList) public procedure LoadFromFile(const FileName: string); override; end; procedure TImportStringList.LoadFromFile(const FileName: string); begin inherited; if count = 0 then raise EBadImportFile.CreateFmt('Datei %s ist leer', [FileName]); end; Man kann kleine Teile der Funktionalität an TImportStringList übertragen (prüfen ob Datei leer ist) und ausserdem bekommt man bei einem Speicherleck gezielte Info wo zu suchen ist. Die ganzen Punkte oben gelten speziell für sehr grosse Anwendungen mit Hunderten von Units. Bei kleinen Anwendungen braucht man nicht so viel Aufwand zu treiben. |
AW: Memory Leak: Ursache finden
Hallo zusammen,
falls sich noch jemand für die Erklärung interessiert: Es ist wirklich das 'FillChar', aber nur, weil es falsch angewandt wurde: Statt 'FillChar( fHfgkFarbe, SizeOf( fHfgkFarbe ), 0)' muss es 'FillChar( fHfgkFarbe[0], Length(fHfgkFarbe)*SizeOf(ein element davon), 0)' heißen. Die obere Zeile leert nur die Feldvariable, aber der damit verbundene Speicherblock mit dem eigentlichen Feldinhalt ist ab dann für den Delphi-Speichermanager unsichtbar. Gruß vom Bären! |
AW: Memory Leak: Ursache finden
@BerlinärBär Die Ursache für das Speicherleck wurde schon in #20 genannt.
|
AW: Memory Leak: Ursache finden
@Blup: Ups, war wohl selektives Lesen...
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:42 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