Ich habe eine GUI-Anwendung, die keinen Speicherverlust hat . Ich habe dies mit FastMM über zahlreiche Testzyklen bestätigt. Auf einem bestimmten Client-Server bekomme ich zufällige Abstürze. Die Serverspezifikationen stimmen gut mit denen unserer anderen Clients überein (und wir haben tatsächlich verschiedene Hardware ausprobiert), und so sind auch die vom Programm verwendeten Dateien (soweit ich das beurteilen kann) gibt es supersensitives Material, das ich kann nicht zugreifen, aber es scheint dort nichts Ungewöhnliches zu sein).
Ich habe EurekaLog und MadShi ausprobiert, um das Problem vielleicht einzugrenzen, aber leider scheinen sie nur gelegentlich eine Ausnahme zu machen, nicht immer. Wenn dies der Fall ist, zeigt es normalerweise einen oder mehrere "Nicht genügend Speicher" Fehler vor dem Absturz.
Ich denke also, dass manche Objekte "zu spät" freigegeben werden, d. h. nur wenn die Anwendung heruntergefahren wird, im Gegensatz dazu, wenn ich sie freilassen möchte? Ich habe die FastMMUsageeTracker-Demo gesehen, konnte aber nicht wirklich einen Sinn ergeben. Gibt es irgendwo Dokumentation? Oder könnte jemand (leicht zugängliche) Worte eingeben, wie ich das überprüfen könnte?
Alternativ, was wäre der beste Ansatz, um zu erkennen, dass sich die Anwendung ihrem "Speicherlimit" nähert, um einige vorbeugende Maßnahmen zu ergreifen? Wenn ich richtig verstehe, sollte eine reguläre Delphi-App mit 32bit, sollte es in Ordnung sein, bis zu 2 GB Speicher (vorausgesetzt, die Hardware unterstützt es natürlich), richtig?
PS: Delphi 2009 oder XE, wenn das relevant ist
Danke!
BEARBEITEN - Problem möglicherweise gelöst
Wir konnten ein Problem finden, bei dem ein Popup-Fenster, das sich nach einer Weile automatisch schließt und wieder freigibt, viel schneller erstellt wurde als es verschwand. Dies würde im Laufe der Zeit eine große Menge an Speicher verbrauchen, und dann würde jede Speicherzuweisung es über den Rand bringen und das "nicht genügend Speicher" -Problem auslösen.
Dies würde erklären, warum die Stacks inkonsistent sind.
Ich bin nicht ganz davon überzeugt, dass dies unser einziges Problem ist, da dieses Szenario, obwohl es unwahrscheinlich ist, in den Jahren, in denen unsere Anwendung läuft, schon passiert sein könnte, aber irgendwie nicht. Ich werde viel mehr zu diesem Thema tun.
Vielen Dank an alle, die geantwortet haben, jede Antwort enthält wertvolle Informationen.
Wenn Sie Delphi XE haben, wird es mit AQTime geliefert, und AQTime hat einen Speicherzuordnungsprofiler als Teil seiner Trickkiste. Wenn Sie das in Ihrem Programm ausführen, können Sie möglicherweise sehen, wohin Ihr RAM geht.
Vergessen Sie "Windows" Speicher - was Sie wollen ist der tatsächliche Speicher von der Anwendung zugewiesen. Nur so können Sie feststellen, ob Sie Speicher reservieren, der nicht im Laufe der Zeit freigegeben wird. Für Delphi 2006+ mit FastMM benötigen Sie Folgendes:
%Vor%Ich logge das in einem Intervall (irgendwo zwischen 10 Sekunden und 10 Minuten) in meine Protokolldatei ein, zusammen mit dem Unterschied zum letzten Mal.
Sie können herausfinden, wie viel Speicher Ihre Anwendung verwendet - sehen Sie diese Seite . Zusammenfassung:
%Vor%Wenn Sie diesen Wert regelmäßig auf Ihrem Server protokollieren, bekommen Sie zumindest eine Vorstellung davon, was gerade passiert. Es gibt mehr Informationen in diesem Ergebnis, die Ihnen helfen sollten, mehr darüber zu erfahren, was Ihr Programm macht.
Der Fix wird sein, um zu sehen, was den Speicher tatsächlich nutzt, und diesen aggressiver zu verwalten. Ich vermute, es wird irgendwo sein, dass du Objekte erstellst und sie nur beim Herunterfahren frei gibst, wenn du sie freigeben kannst (und solltest), sobald du damit fertig bist.
Eine mögliche Lösung besteht darin, den Schalter / 3GB in der Vollversion von FastMM zu verwenden, um zu sehen, ob das Problem länger dauert.
Wenn Sie spektakulär unglücklich sind, haben Sie den Memory Pool Management-Algorithmus von FastMM "gebrochen", so dass er niemals Speicher freigibt ( eine verwandte Frage ). Der Versuch, verschiedene Speichermanager zu verwenden, kann Ihnen dabei helfen, dass einige den unbenutzten Speicher aggressiver zurückgewinnen. Aber wenn Sie Ihren Heapspeicher fragmentieren, ist die einzige wirkliche Lösung, wie Sie das vermeiden können. Was ein komplexes Thema ist, so nochmal: Probier die einfachen Dinge zuerst aus.
Können Sie uns einen Stack-Trace zeigen, wenn Sie den Fehler erhalten? Wie viel Speicher verbraucht es zum Zeitpunkt des Fehlers?
Ich habe vor einiger Zeit einen Speicherlogger (für FastMM) erstellt, der den gesamten Speicher zwischen zwei Punkten protokolliert (mittels einer "startlog" - und "endlog" -Prozedur), um ein "weiches Leck" zu finden: Ich war Zuordnungsobjekte in einer Liste löscht die Liste nie, nur beim Schließen der App, so dass FastMM kein Leck gemeldet hat. Mit meinem Speicherlogger konnte ich diese Objekte finden (es wird nur neuer zugewiesener Speicher protokolliert, der nicht freigegeben wurde, bevor Sie die Prozedur "endlog" ausführen).
Ich werde sehen, ob ich diesen Code finden kann.
Btw: Sie können einen "nicht genügend Speicher" auf 3 andere Arten bekommen:
Geben Sie also eine Stack-Trace und Speichermenge an, die zum Zeitpunkt des Fehlers verwendet wurde!
Mit der Einschränkung von Delphi auf 32-Bit-Adressraum werden solche Probleme immer häufiger.
Die erste und einfachste Sache, die Sie tun können, ist, auf einem 64-Bit-Betriebssystem zu laufen und von 2 GB verfügbarem Adressraum (wie Sie es von einem 32-Bit-Betriebssystem bekommen) auf 4 GB-Adresse zu wechseln. Dies geschieht nicht automatisch. Sie müssen Ihre Anwendung als Largeaddressware kennzeichnen. Tun Sie dies, indem Sie Ihrer .dpr-Datei Folgendes hinzufügen:
%Vor%Der andere häufige Grund für nicht genügend Arbeitsspeicherfehler ist nicht, dass eine Arbeitsspeicherspeicherung vorhanden ist, sondern dass Sie nach einem großen Block zusammenhängenden Arbeitsspeichers fragen und dass kein zusammenhängender Block aus Adressraum verfügbar ist.
Der Umgang mit diesem Problem ist schwieriger. Sie müssen zuerst die Teile Ihres Codes identifizieren, die derzeit große zusammenhängende Speicherblöcke erfordern. Als nächstes müssen Sie die Objekte, die dies tun, modifizieren und veranlassen, dass sie stattdessen nach kleinen Stücken von Speicher fragen, die Sie dann "zusammenheften" können, um das Aussehen eines größeren Blocks zu erhalten. Dies passiert in der Regel mit Code, der nach meiner Erfahrung dynamische Arrays verwendet.
Wenn ich einen "Out of memory" -Fehler bekommen habe, lag das an einer Runaway-Schleife. Die Schleife würde normalerweise Speicher reservieren und würde nicht anhalten, bevor der gesamte verfügbare Speicher verwendet worden wäre. Das Freigeben von Speicher war kein Problem, da das Programm nie an diesen Punkt ging. Arten von Code, die mir gebissen wurden, sind:
Eine "while not x.Eof do" -Schleife ohne "x.Next", um durch das Dataset zu gehen, oder
eine rekursive Prozedur oder Subroutine, die niemals die Beendigungsbedingung (en) gefunden hat.
Ich würde nach irgendeiner Art von Schleife oder Rekursion suchen, die unter bestimmten Umständen "für immer" weiterlaufen könnte, wie zum Beispiel das Erstellen einer Datenstruktur im Speicher, die massiv ist.
Tags und Links memory delphi out-of-memory