Speicherlecks verstehen und verhindern

Delphis Unterstützung für objektorientierte Programmierung ist umfangreich und leistungsstark. Klassen und Objekte ermöglichen eine modulare Code-Programmierung. Zusammen mit modulareren und komplexeren Komponenten kommen anspruchsvollere und komplexere Fehler.

Während das Entwickeln von Anwendungen in Delphi (fast) immer Spaß macht, gibt es Situationen, in denen Sie das Gefühl haben, die ganze Welt sei gegen Sie.

Wann immer Sie ein Objekt in Delphi verwenden (erstellen) müssen Sie den Speicher freigeben, den es verbraucht (sobald es nicht mehr benötigt wird). Die try / finally-Speicherschutzblöcke können Ihnen sicherlich dabei helfen, Speicherverluste zu verhindern. Es liegt immer noch an Ihnen, Ihren Code zu schützen.

Ein Speicherverlust (oder ein Ressourcenverlust) tritt auf, wenn das Programm die Fähigkeit verliert, den verbrauchten Speicher freizugeben. Wiederholte Speicherverluste führen dazu, dass die Speichernutzung eines Prozesses unbegrenzt zunimmt. Speicherverluste stellen ein ernstes Problem dar. Wenn Sie einen Code haben, der Speicherverluste verursacht, wird in einer rund um die Uhr laufenden Anwendung der gesamte verfügbare Speicher verbraucht und der Computer reagiert schließlich nicht mehr.

Speicherlecks in Delphi

Der erste Schritt, um Speicherverluste zu vermeiden, besteht darin, zu verstehen, wie sie auftreten. Was folgt, ist eine Diskussion über einige häufige Fallstricke und bewährte Methoden zum Schreiben von nicht leckendem Delphi-Code.

In den meisten (einfachen) Delphi-Anwendungen, in denen Sie die Komponenten (Schaltflächen, Memos, Bearbeitungen usw.) verwenden, die Sie (zur Entwurfszeit) auf einem Formular ablegen, müssen Sie sich nicht zu sehr um die Speicherverwaltung kümmern. Sobald die Komponente in einem Formular platziert wurde, wird das Formular zu ihrem Besitzer und gibt den von der Komponente beanspruchten Speicher frei, sobald das Formular geschlossen (zerstört) wird. Form ist als Eigentümer für die Speicherfreigabe der von ihr gehosteten Komponenten verantwortlich. Kurz gesagt: Komponenten in einem Formular werden automatisch erstellt und gelöscht

Beispiele für Speicherlecks

In jeder nicht trivialen Delphi-Anwendung möchten Sie Delphi-Komponenten zur Laufzeit instanziieren. Sie werden auch einige Ihrer eigenen benutzerdefinierten Klassen haben. Angenommen, Sie haben eine Klasse TDeveloper mit einer Methode DoProgram. Wenn Sie jetzt die TDeveloper-Klasse verwenden müssen, erstellen Sie eine Instanz der Klasse, indem Sie die aufrufen Erstellen Methode (Konstruktor). Die Create-Methode reserviert Speicher für ein neues Objekt und gibt einen Verweis auf das Objekt zurück.

var
zarko: TDeveloper
Start
zarko: = TMyObject.Create;
zarko.DoProgram;
Ende;

Und hier ist ein einfaches Speicherleck!

Wann immer Sie ein Objekt erstellen, müssen Sie den von ihm belegten Speicher löschen. Um den Speicher eines zugeordneten Objekts freizugeben, müssen Sie die aufrufen Kostenlos Methode. Um ganz sicher zu gehen, sollten Sie auch den try / finally-Block verwenden:

var
zarko: TDeveloper
Start
zarko: = TMyObject.Create;
Versuchen
zarko.DoProgram;
schließlich
zarko.Free;
Ende;
Ende;

Dies ist ein Beispiel für eine sichere Speicherzuweisung und einen Freigabecode.

Einige warnende Worte: Wenn Sie eine Delphi-Komponente dynamisch instanziieren und später explizit freigeben möchten, übergeben Sie immer nil als Eigentümer. Andernfalls können unnötige Risiken sowie Leistungs- und Code-Wartungsprobleme auftreten.

Neben dem Erstellen und Löschen von Objekten mit den Methoden Create und Free müssen Sie auch beim Verwenden von "externen" Ressourcen (Dateien, Datenbanken usw.) sehr vorsichtig sein.
Angenommen, Sie müssen eine Textdatei bearbeiten. In einem sehr einfachen Szenario, in dem die AssignFile-Methode verwendet wird, um eine Datei auf einem Datenträger einer Dateivariablen zuzuordnen, wenn Sie mit der Datei fertig sind, müssen Sie CloseFile aufrufen, um das Dateihandle für die Verwendung freizugeben. Hier haben Sie keinen expliziten Anruf bei "Free".

var
F: TextFile;
S: String;
Start
AssignFile (F, 'c: \ somefile.txt');
Versuchen
ReadIn (F, S);
schließlich
CloseFile (F);
Ende;
Ende;

Ein weiteres Beispiel ist das Laden externer DLLs aus Ihrem Code. Wann immer Sie LoadLibrary verwenden, müssen Sie FreeLibrary aufrufen:

var
dllHandle: THandle;
Start
dllHandle: = Loadlibrary ('MyLibrary.DLL');
// mach etwas mit dieser DLL
wenn dllHandle 0, dann FreeLibrary (dllHandle);
Ende;

Speicherverluste in .NET?

Obwohl mit Delphi für .NET der Garbage Collector (GC) die meisten Speicheraufgaben verwaltet, kann es in .NET-Anwendungen zu Speicherverlusten kommen. Hier ist ein Artikel über GC in Delphi für .NET.

Wie man gegen Speicherlecks kämpft

Neben dem Schreiben von modularem speichersicherem Code können Sie mithilfe einiger Tools von Drittanbietern Speicherverluste verhindern. Mit Delphi Memory Leak Fix Tools können Sie Delphi-Anwendungsfehler wie Speicherbeschädigung, Speicherlecks, Speicherzuordnungsfehler, Variableninitialisierungsfehler, Variablendefinitionskonflikte, Zeigerfehler und mehr abfangen.