Computerwissenschaften

Optimieren der Speichernutzung Ihres Delphi-Programms

Beim Schreiben langer Laufzeit- Anwendungen – die Art von Programmen , die in der Taskleiste oder minimiert meiste Zeit des Tages verbringen System – Tray kann es wichtig werden , nicht das Programm ‚weglaufen‘ zu lassen , mit der Speichernutzung.

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

01 von 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 Punkte stark beeinträchtigt, wird Ihr System langsamer.

Die Art von Dingen, die sich häufig auf die CPU-Auslastung auswirken, ist ein Programm, das sich in einer Schleife befindet (fragen Sie jeden Programmierer, der vergessen hat, eine „read next“ -Anweisung in eine Dateiverarbeitungsschleife einzufügen). Diese Art von Problemen lässt sich normalerweise leicht beheben.

Die Speichernutzung ist dagegen nicht immer offensichtlich und muss mehr als korrigiert verwaltet 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 wieder hochzufahren. Es wird den ganzen Tag über verwendet, allerdings in seltenen Abständen.

Wenn dieses Programm auf einer starken internen Verarbeitung beruht oder viele Grafiken in seinen Formularen enthalten, wird früher oder später die Speichernutzung zunehmen, wodurch weniger Speicher für andere häufigere Prozesse übrig bleibt, die Paging-Aktivität erhöht und letztendlich der Computer verlangsamt wird .

02 von 06

Wann Sie Formulare in Ihren Delphi-Anwendungen erstellen

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

Die in der Projekteinheit enthaltenen Linien stammen von Delphi und eignen sich hervorragend für Personen, die mit Delphi nicht vertraut sind oder es gerade erst verwenden. Es ist bequem und hilfreich. Dies bedeutet auch, dass ALLE Formulare beim Start des Programms erstellt werden und NICHT, wenn sie benötigt werden.

Abhängig davon, worum es in Ihrem Projekt geht und welche Funktionen Sie für ein Formular implementiert haben, kann viel Speicherplatz benötigt werden. Daher sollten Formulare (oder allgemein: Objekte) nur bei Bedarf erstellt und zerstört (freigegeben) werden, sobald 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 der „automatisch erstellten Formulare“ entfernt und in die Liste „Verfügbare Formulare“ verschoben werden.

03 von 06

Zuschneiden des zugewiesenen Speichers: Nicht so dumm wie Windows

Stanislaw Pytel / Getty Images

Bitte beachten Sie, dass die hier beschriebene Strategie auf der Annahme basiert, dass es sich bei dem betreffenden Programm um ein Echtzeitprogramm vom Typ „Capture“ handelt. Es kann jedoch leicht für Chargenprozesse angepasst werden.

 

Windows- und Speicherzuordnung

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

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

Sobald Windows einem Prozess einen Speicherblock zugewiesen hat und dieser Prozess 99,9% des Speichers freigibt, erkennt Windows weiterhin, dass der gesamte Block verwendet wird, selbst wenn nur ein Byte des Blocks tatsächlich verwendet wird. Die gute Nachricht ist, dass Windows einen Mechanismus zur Behebung dieses Problems bietet. Die Shell bietet uns eine API namens SetProcessWorkingSetSize . Hier ist die Unterschrift:


SetProcessWorkingSetSize ( 
hProcess: HANDLE; 
MinimumWorkingSetSize: DWORD; 
MaximumWorkingSetSize: DWORD);

04 von 06

Die All Mighty SetProcessWorkingSetSize-API-Funktion

Sirijit Jongcharoenkulchai / EyeEm / Getty Images

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

Diese API soll eine Einstellung der minimalen und maximalen Speichergrenzen für den Speicherbedarf des Prozesses auf niedriger Ebene ermöglichen. Es ist jedoch eine kleine Eigenart eingebaut, die am glücklichsten ist.

Wenn sowohl der minimale als auch der maximale Wert auf $ FFFFFFFF festgelegt sind, schneidet die API die festgelegte Größe vorübergehend auf 0, tauscht sie aus dem Speicher aus, und sofort, wenn sie wieder in den RAM zurückspringt, wird ihr die minimale Mindestmenge an Speicher zugewiesen dazu (dies alles geschieht innerhalb weniger Nanosekunden, daher sollte es für den Benutzer nicht wahrnehmbar sein).

Ein Aufruf dieser API erfolgt nur in bestimmten Intervallen – nicht kontinuierlich, daher sollte die Leistung überhaupt nicht beeinträchtigt werden.

Wir müssen auf ein paar Dinge achten:

  1. Das Handle, auf das hier Bezug genommen wird, 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 angesehen wird. Der Grund dafür ist, dass wir nicht möchten, dass der Speicher genau zu dem Zeitpunkt entfernt wird, zu dem eine Verarbeitung (ein Knopfdruck, ein Tastendruck, eine Kontrollshow usw.) bevorsteht oder stattfindet. In diesem Fall besteht das ernsthafte Risiko von Zugriffsverletzungen.

05 von 06

Reduzieren der Speichernutzung bei Erzwingung

Morsa Images / Getty Images

In diesem  Code haben wir es so festgelegt:

Erstellen Sie eine globale Variable, um die zuletzt aufgezeichnete Anzahl von Ticks im Hauptformular zu speichern. Zu jedem Zeitpunkt, zu dem eine Tastatur- oder Mausaktivität vorliegt, wird die Anzahl der Ticks aufgezeichnet.

Überprüfen Sie nun regelmäßig die Anzahl der letzten Ticks gegen „Jetzt“. Wenn der Unterschied zwischen beiden größer ist als der Zeitraum, der als sichere Leerlaufzeit angesehen wird, kürzen Sie den Speicher.


 var
LastTick: DWORD;

Legen Sie eine ApplicationEvents-Komponente im Hauptformular ab. In seiner OnMessage Ereignishandler den folgenden Code eingeben:


 procedure TMainForm.ApplicationEvents1Message ( var Msg: tagMSG; var Handled: Boolean); 
 begin 
   case Msg.message von
  WM_RBUTTONDOWN, 
 WM_RBUTTONDBLCLK, 
 WM_LBUTTONDOWN, 
 WM_LBUTTONDBLCLK, 
 WM_KEYDOWN: 
   LastTick:=GetTickCount; 
   Ende ; 
 Ende ;

Entscheiden Sie nun, nach welcher Zeit 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. Stellen Sie das Intervall auf 30000 (30 Sekunden) ein und geben Sie im Ereignis „OnTimer“ die folgende einzeilige Anweisung ein:


 Prozedur TMainForm.Timer1Timer (Absender: TObject); 
 begin 
   if (((GetTickCount - LastTick) / 1000)> 120) oder (Self.WindowState=wsMinimized) then TrimAppMemorySize; 
 Ende ;

 

Anpassung für lange Prozesse oder Stapelverarbeitungsprogramme

Die Anpassung dieser Methode an lange Verarbeitungszeiten oder Batch-Prozesse ist recht einfach. Normalerweise haben Sie eine gute Vorstellung davon, wo ein langer Prozess beginnt (z. B. Beginn einer Schleife, die Millionen von Datenbankeinträgen liest) und wo er endet (Ende der Datenbankleseschleife).

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

Similar Posts

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.