![]() |
Speicher sparen und Geschwindigeit erhöhen
Hallo alle!
ich hab mal wieder ein neues Problem. Ich habe vor einen Urlaubsplaner zu schreiben, das Problem ist auch nicht der Code oder die Logik oder so. Ich habe das Problem das mein Urlaubsplaner recht langsam ist, und je mehr elemente ich in mein Dynamisches Array hänge desto länger braucht er um ein einzelnes Element anzuhängen. Ich habe mir ausgerechnet was ein Objekt anhand meiner Variablen für Speicher verbrauchen würde. Aber wenn ich meinen verbrauchten Speicher nach dem laden durch die anzahl der tage*personen teile bekomme ich einen viel größeren wert für ein element raus :( Meine beiden Probleme sind also die typischen: Wie spare ich Speicher und wie bekomm ich den ganzen kram schneller? anstatt eines dynamischen arrays eine tlist benutzen? oder doch lieber selber ne zweifach verkettte dynamische liste (müsste vom prinzip ja sowas sein wie die tlist, halt bloss selber)? ich weiss da echt nicht weiter. Ich habe getestet auf ner guten maschine (p4-2ghz,256mb) und er hat bei 11 personen für das ganze jahr 2003 8mb speicher verballert und 15 sek. gebraucht. bei 70 personen habe ich nach 5 minuten und 150mb das programm abgebrochen :(( nachstehend mal n bisschen code:
Delphi-Quellcode:
erstellen tu ich das ganze über meinen constructor und indem ich type TMyCoords = Packed Record Column: Word; Row: Word; Top: Word; Left: Word; Bottom: Word; Right: Word; End; TMyInformation = Packed Record msdDay: TDate; msdWDay: String[12]; msdPerson: String[50]; msdPersonNR: String[5]; msdActualKosten: String[5]; msdNormalKosten: String[5]; End; TMySpecialDay = class(TShape) mytitel: TStaticText; constructor NCreate ( how: TCreateIt ); // Constructor destructor Destroy; override; // Destructor private msdID: Integer; msdState: Word; // --- msdCoords: TMyCoords; msdInfo: TMyInformation; // --- msdChanged: Boolean; msdStatebeforeChange: Word; msdSelected: Boolean; public procedure onMyMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure onMyMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure onMyMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure CreateLabel(var Lbl: TStaticText; X,Y,W,H: Integer; BorderStyle: TStaticBorderStyle; Color,FontColor: TColor; FontStyle: TFontStyles; Capt: String; Align: TAlignment; FontSize: Integer); end; var mySD: Array of TMySpecialDay; das array mit setlength(length + 1) erhöhe. Weiss da jemand Rat? mfg, Mika |
Hallo mika
wass machst du wenn du das Array vergrößerst? |
Der Delphi-Speichermanager hat ein Problem, wenn man ein Array laufend vergrößert.
Hier mal zur Verdeutlichung: 1. Code:
Delphi-Quellcode:
2. Code:
SetLength(100000);
for i := 0 to 100000 - 1 do a[High(a)] := TMyObject.Create;
Delphi-Quellcode:
Das Ergebnis beider Codes ist identisch. Der Speicherverbrauch hingegen nicht. Rein rechnerisch kommt man beim Speicherverbrauch zwar auf diesselben Werte, aber die Realität zeigt etwas anderes:
a := nil;
for i := 0 to 100000 - 1 do begin SetLength(a, Length(a) + 1); a[High(a)] := TObject.Create; end; 1. Code: a belegt ca. 4 MB 2. Code: a belegt ca. 120 MB Das ganze hat mit Speicherlöchern zu tun. So wird beim 1. Code der gesamte Speicher für das Array auf einmal belegt. Beim 2. Code hingegen wird immer wieder vergrößert. Dieses Vergrößern hat zur Folge, dass das neue Array nicht mehr in den alten Speicherbereich passt und somit ein neuer, der das Array aufnehmen kann, reserviert werden muss. Der alte bleibt aber für Windows belegt, da Delphi diesen nicht freigibt, weil er ja Programmintern wieder verwendet werden kann. Nur eben nicht von unserem Array, das zu Groß dafür ist. Da sich aus diesem Grund der Speicherverbrauch der Anwendung immens erhöht, bleibt Windows kein RAM mehr und es muss auslagern, was die Performance in die Knie zwingt. Wenn man jedoch auf des "immer wieder Vergrößern" nicht verzichten kann, muss ein anderer Speichermanager her. Ein einfacher, jedoch langsamer ist die nutzung von HeapAlloc, HeapFree und HeapRealloc, die man mit SetMemoryManager durch GetMem, FreeMem und ReallocMem aufrufen kann. Eine Kombination aus Delphi-Speichermanager und den HeapXxx API Funktionen brachte mir bis jetzt die besten Ergenisse, was Geschwindigkeit und Speicherverbrauch angeht. Um es aber nicht nur auf Borland zu schieben: Auch der Speichermanager von C/C++ (malloc@msvcrtxx.dll) hat dieses Problem und der stammt von Microsoft. |
Array nacher wieder freigegeben
Hallo an alle,
erstmal danke für die Antworten! Das mit dem beispiel von 4 und 120 MB klingt echt interessant, ich probier das gleich mal aus! aber ich hatte schon mal das problem wenn ich ein Dynamisches Array wieder freigeben will das ich auf "einen Schlag" komplett reserviert hatte. Ich probier das jetzt mal aus und melde mich heute abend wieder, wirklich höchst interessant! Danke! mdf, mika |
Kuck mal hier, da gibts einen ersatz für den Memory Manager der angeblich um einiges besser arbeitet als das Original:
![]() vielleicht bringts ja was... |
Dieser ist besser. Nur stört mich daran eine Sache: Der belegte Speicher wird erst beim Programmende wieder freigegeben. Das ist nicht gerade performancesteifernd für andere Anwendungen und bekannlich ist Windows ein Multitasking Betriebsystem.
Wenn die Anwendung also für kurze Zeit 200 MB benötigt, dann bleiben diese 200 MB bis zum Programmende dem Programm zugeordnet und stehen nicht für andere Programme zur Verfügung. |
mich interessiert dieses thema auch gerade
ich habe hier eine komponente geschrieben ![]() die es ermöglicht, struckturierte dateien zu laden das problem an der sache, nach dem laden der datei, verbraucht das programm mehr als das 100 fache von der eigendlichen grösse der zu lesenden datei bsp. die datei ist 2,.. mb gross, der windowns taskmaneger zeigt mir 299,...kb an ... |
Liste der Anhänge anzeigen (Anzahl: 1)
Dabei handelt es sich um genau dasselbe Problem. Beim Hinzufügen vergrößerst du das Array immer um eins.
Wem der obige Speichermanager nicht behaart, da er den verwendeten Speicher nicht wieder freigibt, der kann meinen einsetzen. Dieser nutzt den vorhandenen Speichermanager und nach 10-maligem Aufruf von ReallocMem() für einen Speicherbereich wird der Speicher auf den ProcessHeap geschoben, der zwar beim reservieren langsamer als der von Delphi verwendete Speicher ist, aber eben nicht dieses Manko aufweist. |
das gucke ich mir mal an, danke :)
|
Bedenke, dass die Unit als allererste im Projektquellcode eingebunden wird.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:26 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