Hinweise

Optimieren der Speichernutzung Ihres Delphi-Programms

Optimieren der Speichernutzung Ihres Delphi-Programms

Beim Schreiben von Anwendungen mit langer Laufzeit - die Art von Programmen, die den größten Teil des Tages auf die Taskleiste oder die Taskleiste beschränkt sind - kann es wichtig werden, das Programm nicht mit der Speichernutzung "weglaufen" zu lassen.

Erfahren Sie, wie Sie den von Ihrem Delphi-Programm verwendeten Speicher mit der SetProcessWorkingSetSize-Windows-API-Funktion bereinigen.

01von 06

Was hält Windows von der Speichernutzung Ihres Programms?

Schauen Sie sich den Screenshot des Windows Task Managers an…

Die beiden Spalten ganz rechts geben die CPU-Auslastung (Zeit) und die Speichernutzung an. Wenn ein Prozess einen dieser schwerwiegenden Auswirkungen hat, wird Ihr System langsamer.

Die Art von Dingen, die sich häufig auf die CPU-Auslastung auswirken, ist ein Programm, das eine Schleife durchläuft (fragen Sie jeden Programmierer, der vergessen hat, eine "read next" -Anweisung in eine Dateiverarbeitungsschleife einzufügen). Solche Probleme lassen sich normalerweise leicht beheben.

Andererseits ist die Speichernutzung nicht immer offensichtlich und muss mehr als korrigiert werden. Angenommen, ein Capture-Programm wird ausgeführt.

Dieses Programm wird den ganzen Tag über verwendet, möglicherweise für die telefonische Erfassung an einem Helpdesk oder aus einem anderen Grund. Es macht einfach keinen Sinn, es alle zwanzig Minuten herunterzufahren und dann neu zu starten. Es wird den ganzen Tag über verwendet, wenn auch in seltenen Abständen.

Wenn sich dieses Programm auf eine starke interne Verarbeitung stützt oder viele Grafiken auf seinen Formularen hat, wird die Speichernutzung früher oder später zunehmen, wodurch weniger Speicher für andere häufigere Prozesse übrig bleibt, die Paging-Aktivität erhöht und der Computer letztendlich verlangsamt wird .

02von 06

Zeitpunkt zum Erstellen von Formularen in Delphi-Anwendungen

Angenommen, Sie entwerfen ein Programm mit dem Hauptformular und zwei zusätzlichen (modalen) Formularen. Abhängig von Ihrer Delphi-Version fügt Delphi in der Regel die Formulare in die Projekteinheit (DPR-Datei) ein und fügt beim Start der Anwendung eine Zeile zum Erstellen aller Formulare ein (Application.CreateForm (…)

Die in der Projekteinheit enthaltenen Zeilen sind von Delphi-Design und eignen sich hervorragend für Personen, die mit Delphi nicht vertraut sind oder es gerade erst verwenden. Es ist praktisch und hilfreich. Dies bedeutet auch, dass ALLE Formulare erstellt werden, wenn das Programm gestartet wird und NICHT, wenn sie benötigt werden.

Abhängig davon, worum es in Ihrem Projekt geht und welche Funktionen Sie implementiert haben, kann ein Formular viel Speicherplatz beanspruchen. Daher sollten Formulare (oder allgemein: Objekte) nur dann erstellt und zerstört (freigegeben) werden, wenn sie nicht mehr benötigt werden .

Wenn "MainForm" das Hauptformular der Anwendung ist, muss es das einzige Formular sein, das beim Start im obigen Beispiel erstellt wurde.

Sowohl "DialogForm" als auch "OccasionalForm" müssen aus der Liste "Automatisch erstellte Formulare" entfernt und in die Liste "Verfügbare Formulare" verschoben werden.

03von 06

Zugewiesenen Speicher verkleinern: Nicht so einfach wie Windows

Stanislaw Pytel / Getty Images

Bitte beachten Sie, dass die hier beschriebene Strategie auf der Annahme basiert, dass es sich bei dem fraglichen Programm um ein Echtzeit-Capture-Programm handelt. Es kann jedoch leicht für Chargenprozesse angepasst werden.

Windows- und Speicherzuordnung

Windows hat eine ziemlich ineffiziente Methode, seinen Prozessen Speicher zuzuweisen. Es ordnet Speicher in signifikant großen Blöcken zu.

Delphi hat versucht, dies zu minimieren und verfügt über eine eigene Speicherverwaltungsarchitektur, die viel kleinere Blöcke verwendet. In der Windows-Umgebung ist dies jedoch praktisch nutzlos, da die Speicherzuordnung letztendlich beim Betriebssystem liegt.

Sobald Windows einem Prozess einen Speicherblock zugewiesen hat und dieser Prozess 99,9% des Speichers freigibt, erkennt Windows den gesamten Block weiterhin als belegt, auch wenn nur ein Byte des Blocks tatsächlich verwendet wird. Die gute Nachricht ist, dass Windows einen Mechanismus zur Bereinigung dieses Problems bietet. Die Shell stellt uns eine API namens zur Verfügung SetProcessWorkingSetSize. Hier ist die Unterschrift:

SetProcessWorkingSetSize (
hProzess: HANDLE;
MinimumWorkingSetSize: DWORD;
MaximumWorkingSetSize: DWORD);04von 06

Die All Mighty SetProcessWorkingSetSize-API-Funktion

Sirijit Jongcharoenkulchai / EyeEm / Getty Images

Per Definition legt die SetProcessWorkingSetSize-Funktion die minimalen und maximalen Arbeitsgruppengrößen für den angegebenen Prozess fest.

Diese API soll das Festlegen der minimalen und maximalen Speichergrenzen für den Speicherbedarf des Prozesses auf niedriger Ebene ermöglichen. Es hat jedoch eine kleine Eigenheit eingebaut, was das größte Glück ist.

Wenn sowohl der minimale als auch der maximale Wert auf $ FFFFFFFF gesetzt sind, schneidet die API die festgelegte Größe vorübergehend auf 0 ab, verschiebt sie aus dem Arbeitsspeicher und sobald sie wieder in den Arbeitsspeicher zurückspringt, wird ihr nur die minimale Menge an Arbeitsspeicher zugewiesen dazu (dies alles geschieht innerhalb von ein paar Nanosekunden, so dass es für den Benutzer nicht wahrnehmbar sein sollte).

Ein Aufruf dieser API erfolgt nur in bestimmten Intervallen - nicht kontinuierlich, sodass die Leistung in keiner Weise beeinträchtigt werden sollte.

Wir müssen auf ein paar Dinge achten:

  1. Das hier genannte Handle ist das Prozesshandle, NICHT das Hauptformularhandle (daher können wir nicht einfach "Handle" oder "Self.Handle" verwenden).
  2. Wir können diese API nicht wahllos aufrufen. Wir müssen versuchen, sie aufzurufen, wenn das Programm als inaktiv eingestuft wird. Der Grund dafür ist, dass wir nicht möchten, dass der Speicher genau zu dem Zeitpunkt abgeschnitten wird, an dem eine Verarbeitung (ein Tastenklick, ein Tastendruck, eine Steuerungsshow usw.) stattfinden soll oder wird. In diesem Fall besteht ein ernstes Risiko, dass Zugriffsverletzungen auftreten.
05von 06

Speichernutzung bei erzwungener Verwendung reduzieren

Heldenbilder / Getty Images

Die SetProcessWorkingSetSize-API-Funktion soll das einfache Festlegen der minimalen und maximalen Speichergrenzen für den Speicherbedarf des Prozesses ermöglichen.

Hier ist eine Delphi-Beispielfunktion, die den Aufruf von SetProcessWorkingSetSize umschließt:

Verfahren TrimAppMemorySize;
var
MainHandle: THandle;
Start
  Versuchen
MainHandle: = OpenProcess (PROCESS_ALL_ACCESS, false, GetCurrentProcessID);
SetProcessWorkingSetSize (MainHandle, $ FFFFFFFF, $ FFFFFFFF);
CloseHandle (MainHandle);
  außer
  Ende;
Application.ProcessMessages;
Ende;

Groß! Jetzt haben wir den Mechanismus, um die Speichernutzung zu reduzieren. Das einzige andere Hindernis besteht darin, zu entscheiden, WANN es angerufen wird.

06von 06

TApplicationEvents OnMessage + ein Timer: = TrimAppMemorySize NOW

Morsa Images / Getty Images

In diesem Code haben wir es so festgelegt:

Erstellen Sie im HAUPTFORMULAR eine globale Variable, die die Anzahl der zuletzt aufgezeichneten Ticks enthält. Zu jeder Zeit, in der Tastatur- oder Mausaktivität vorhanden ist, wird die Anzahl der Ticks aufgezeichnet.

Überprüfen Sie nun in regelmäßigen Abständen die Anzahl der letzten Ticks mit „Jetzt“. Wenn die Differenz zwischen den beiden Werten größer ist als der Zeitraum, der als sicherer Leerlauf angesehen wird, kürzen Sie den Speicher.

var
LastTick: DWORD;

Legen Sie eine ApplicationEvents-Komponente im Hauptformular ab. In seinem OnMessage Ereignishandler Geben Sie den folgenden Code ein:

Verfahren TMainForm.ApplicationEvents1Message (var Msg: tagMSG; var Behandelt: Boolean);
Start
  Fall Nachricht von
WM_RBUTTONDOWN,
WM_RBUTTONDBLCLK,
WM_LBUTTONDOWN,
WM_LBUTTONDBLCLK,
WM_KEYDOWN:
LastTick: = GetTickCount;
  Ende;
Ende;

Entscheiden Sie nun, nach welcher Zeitspanne das Programm als inaktiv eingestuft wird. In meinem Fall haben wir uns für zwei Minuten entschieden, aber Sie können je nach den Umständen einen beliebigen Zeitraum auswählen.

Legen Sie einen Timer auf dem Hauptformular ab. Setzen Sie das Intervall auf 30000 (30 Sekunden) und geben Sie im Ereignis "OnTimer" die folgende einzeilige Anweisung ein:

Verfahren TMainForm.Timer1Timer (Absender: TObject);
Start
  ob (((GetTickCount - LastTick) / 1000)> 120) oder (Self.WindowState = wsMinimized) dann TrimAppMemorySize;
Ende;

Anpassung für lange Prozesse oder Batch-Programme

Die Anpassung dieser Methode für lange Bearbeitungszeiten oder Batch-Prozesse ist recht einfach. Normalerweise haben Sie eine gute Vorstellung davon, wo ein langwieriger Prozess beginnen wird (z. B. Beginn einer Schleife, die Millionen von Datenbankeinträgen durchliest) und wo er enden wird (Ende der Datenbank-Leseschleife).

Deaktivieren Sie einfach Ihren Timer zu Beginn des Vorgangs und aktivieren Sie ihn am Ende des Vorgangs erneut.

Schau das Video: Delphi Diagnose software - VW Golf 3 diagnostic - Golf 3 diagnose software (Juni 2020).