![]() |
Speicher läuft voll
Hi...
Ich habe ein Moster-Projekt am laufen, dass diverse Daten aus einer datenbank ausliest und dann spezifische Statistiken und andere Auswertungen ermöglicht. Weil von anfang an nicht ganz klar war in welche Richtung die Entwicklung geht habe ich folgendes gemacht: Ich habe die Datensätze in Form einer Tabelle aus einem dynamischen Array of Array of String aufgebaut. Zu diesem Array gehören diverse weitere dynamische Array of String, die darüber auskunft geben wie das Array interprätiert werden soll (steht eine Zahl drin, wieviele nachkommastellen, ist es eine ID (Personalnummer), die mit einem Text (Name der Person) verknüpft werden muss, bedingte Formatierung mit Farben bei Fall X, Y, Z... Soll die Spalte angezeigt werden, etc...). Auf diese Weise komme ich zu einer stattlichen Ansammlung von dynamischen ein-, zwei- und dreidimensionalen Arrays. Die Arrays werden entweder dynamisch aus einer (mehreren) DLL-deladen oder aus der Datenbank selbst mittels einer TSQLQuerry gezogen. Wenn ich nun Datensätze abfrage - Können schon mal um die 70.000 sein à ca 150Byte (plus die ganzen Referenz-Arrays), ist aber seltener - dann läuft der Speicher mit bis zu 150MB voll. Das ist eine Zahl, die ich aus dem Windows Task manager im Reiter Systemleistung gefunden habe. Programm gestartet, Speicherwert notiert, Abfrage abgesetzt, Speicher notiert, defferenz ermittelt. Puh... Jetzt zu meiner Frage: wenn ich derart große Abfragen starte sind es zwar eine Menge Daten, die da berechnet werden. Aber 150 MB erscheint mir doch ein 'etwas' zu hoher Wert. Wo könnte dieses Phänomen entstehen? Wie kann ich herausfinden was da den Speicher so aufbläht und an welcher Stelle es geschieht. machen es wirklich die Arrays oder läuft die Querry so voll? Kann das sein? Dazu kommt, wenn ich nach so einer Hammer-Abfrage eine kleine (normale) absetze, bleibt der Speicherwert auf dieser zahl stehen - erst wenn ich das Programm beende wird er wieder freigegeben... Sagt diese Zahl im Systemleistungsfenster überhaupt etwas aus oder mach ich mich nur selbst verrückt? Ausserdem kann es bei solchen Mords-Abfragen auch dazu kommen, dass das Programm einen "Fehler in Modul MeinProgramm.exe" ausgibt an Adresse sowiso (ihr wisst schon was ich meine) oder sich mit einer Illegal Pointer-Operation verabschiedet. Das muss direkt mit diesem phänomen zusammenhängen. bei normal dimensionierten Abfragen läuft der Code äusserst stabil... Ich hoffe ich habe halbwegs rübergebracht was ich meine. hoffe und warte... MfG Tonic |
Re: Speicher läuft voll
Check mal dein Programm mittels
![]() Für dein 150 MB-Problem (70.000 sein à ca 150Byte = 150 MB Speicherzuwachs): Hast Du irgendwelche Debug-Infos aktiv? |
Re: Speicher läuft voll
Für alle die die Bedeutung der Suchfunktion kennen...
Die Lösung zu meinem Problem ist relativ einfach gewesen.
Delphi-Quellcode:
Dient dazu ein Array um eins zu vergrößern. Das funktioniert auch wunderbar. Wenn man allerdings das ganze Array so aufbaut - immer um einen vergrößern - und das Array dann echt groß wird, kann dabei der Speicher knapp werden.
setlength(Daten, length(Daten)+1);
Ich erklähre mir das so: Vermutlich muss so ein Array in einem zusammenhängendem Stück Speicher geschrieben werden. Wenn also ein Feld des Arrays 10k groß ist und wir drei Felder haben, so belegt das Array 30k. Wenn nun dieser Block nicht erweitert werden kann auf 40k so wird ein neuer Block im Speicher gesucht, der die 40k aufnehmen kann. Scheinbar wird der alte 30k große Block dabei aber nicht oder nicht sofort freigegeben, so dass wir nun schon 70k Speicher belegen mit Daten, die es überhaupt nicht gibt. Es ist nur eine vermutung, die sich auf folgenden versuch stützt:
Delphi-Quellcode:
Diesen Code habe ich aus dem Gedächtnis getippt - könnte sein, dass er Fehlerbehaftet ist aber sinngemäß stimmt er
test:='0123456789';
for i:=0 to 10000 do begin setlength(Daten, length(Daten)+1); for j:=0 to 10 do begin setlength(Daten[i], length(Daten[i])+1); Daten[i][j]:=test; end; end; Wer nun meint, Das Array müsse 1.000.000 Byte groß sein, der irrt. Zumindest nach meiner oben beschriebenen Messmethode. Fakt ist, es war nicht möglich ein oben beschriebenes Array zu verarbeiten. Die Lösung war darum recht simpel. Ich habe - relativ aufwendig - die Anzahl der zu erwartenden Datensätze ermittelt und das array gleich in diesen Dimensionen gestaltet. Danach stimmte der Speicherverbrauch mit der (geschätzten) Datengröße weitgehend überein. Meine Vermutungen basieren auf Beiträge aus der DP, die ich perönlich für Einleuchtend halte. Mag sein, dass dies ein bekanntes Problem ist. Ich habe mir das jedenfalls selbst erarbeitet 8) :thumb: MfG Tonic |
Re: Speicher läuft voll
Hi!
Ja, die Lösung hast du wohl richtig erkannt. Es gab da gestern/vorgestern auch einen Thread dazu. Darin erklärte Luckie, dass das mit dem Speichmanagement von Borland/Delphi zu tun hat und es nicht wirklich berechenbar wäre, wann der Speicher wieder freigegeben wird. Ciao Frederic |
Re: Speicher läuft voll
Erstmal Respekt, das du dir das selber erarbeitet hast. Das deutet daraufhin, dass dich Delphi-Interna interessieren. Hast also die Besten Vorraussetzungen um ein Super Programmierer zu werden.
Das Problem ist allerdings schon lange bekannt. Zum Beispiel hier: ![]() Eine Lösung ist einen alternative Speichermanager zu verwenden. |
Re: Speicher läuft voll
Zitat:
Das "Problem" (würde es eher als Mishandlung des Speichermanagers bezeichnen) ist aber nicht nur beim Delphi Speichermanager vorhanden, sondern auch der C/C++ Speichermanager malloc/realloc/free hat das "Problem". |
Re: Speicher läuft voll
Wenn ich Dich richtig verstanden habe, dann scheinst Du ja die Ergebnismengen ganzer Queries im RAM ablegen zu wollen.
Also da solltest Du Dir vielleicht lieber eine andere Möglichkeit ausdenken. Solche Datenmengen im RAM abzulegen ist wirklich nicht üblich. Verarbeite die Daten lieber gleich in der Datenbank. |
Re: Speicher läuft voll
Das mit dem RAM ist schon so beabsichtigt gewesen... Es handelt sich um ein recht komplexes Auswerte-Tool, das aus Gründen der Handhabbarkeit so gestrickt ist. Wenn ich viel mit dem Server arbeite verursacht das viel Traffic auf dem Netzwerk einen Spürbaren Lag (mehrere Sekunden) bei der Bedienung. Vermutlich ist der Server ganz schön am schuften wenn mehrere Abteilungen "auf den letzten Drücker" alle ihre Monatsabrechnung machen. Auf diese Weise hat jeder Benutzer nur einen einmaligen Zugriff für ein paar Sekunden und arbeitet dann flüssig mit den lokalen Daten im RAM.
Eine wirklich, wirklich komplexe Abfrage (was übrigens nicht die Regel ist) über mehrer Monate (für die dieses Tool ansich auch garnicht gedacht war - aber danach fragt ein User bekanntlich ja nicht) umfasst nun bis zu 17 MB Arbeisspeicher (alles zusammen incl der geladenen EXE-Datei und DLLs u.s.w.) Ich denke, das ist durchaus vertretbar. Der Thread von Lucki ist an mir vorbeigegangen... :( Aber ich hatte die Lösung auch schon vor dem Wochenende gefunden. Nur noch nicht gepostet, weil ich mir noch nicht sicher war. Ich hab die DP intensiv durchforstet und denke sie wär mir ins Auge gefallen... Das mit dem anderen Speichermanager hat mit Sicherheit nicht nur Vorteile... Ich denke, dass hängt von der eigentlichen Aufgabe ab. Bislang bin ich ganz gut hingekommen mit dem Borland-Speichermanager. MfG Tonic |
Re: Speicher läuft voll
Zitat:
|
Re: Speicher läuft voll
So weit ich weis benutzt doch gerade das dynamische Array/Strings ReallocMem. Der macht doch genau das. Also neuen Speicher anfordern, Speicher kopieren, alten Speicher "freigeben".
Wenn dann müsstest du zum direkt per VirtualAlloc oder so direkt von Windows Speicher anfordern und wieder freigeben. Aber dann ist es einfacher, einen eigene Speichermanager zu basteln (siehe dazu SetMemoryManager und GetMemoryManager). Um den dann aber gut zu optimieren braucht schon seine Zeit, deshalb kann man auch getrost einen alternativen MemManger verwenden. Viele sind sogar besser als Delphi-Manager, weil sie direkt größere Bereiche von Windows anfordern. Also statt 3 x 10 Bytes wird bei der ersten Anforderung von 10 Bytes zum Beispiel direkt 4096 Bytes angefordert. Ich glaube einfach, dass man verschiedene Testen muss, wenn man auf solche Probleme stösst. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:07 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz