Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Speicher sparen und Geschwindigeit erhöhen (https://www.delphipraxis.net/2929-speicher-sparen-und-geschwindigeit-erhoehen.html)

mika 14. Feb 2003 11:38


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:

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;
erstellen tu ich das ganze über meinen constructor und indem ich
das array mit setlength(length + 1) erhöhe.

Weiss da jemand Rat?
mfg, Mika

lodda 14. Feb 2003 12:06

Hallo mika

wass machst du wenn du das Array vergrößerst?

jbg 14. Feb 2003 13:09

Der Delphi-Speichermanager hat ein Problem, wenn man ein Array laufend vergrößert.

Hier mal zur Verdeutlichung:

1. Code:
Delphi-Quellcode:
SetLength(100000);
for i := 0 to 100000 - 1 do
  a[High(a)] := TMyObject.Create;
2. Code:
Delphi-Quellcode:
a := nil;
for i := 0 to 100000 - 1 do
begin
  SetLength(a, Length(a) + 1);
  a[High(a)] := TObject.Create;
end;
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:

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.

mika 14. Feb 2003 16:11

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

janjan 14. Feb 2003 17:34

Kuck mal hier, da gibts einen ersatz für den Memory Manager der angeblich um einiges besser arbeitet als das Original:

http://www.optimalcode.com/memmgr.htm

vielleicht bringts ja was...

jbg 14. Feb 2003 18:09

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.

Snoop007 14. Feb 2003 21:12

mich interessiert dieses thema auch gerade
ich habe hier eine komponente geschrieben
http://www.delphipraxis.net/viewtopic.php?t=3205
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 ...

jbg 14. Feb 2003 21:48

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.

Snoop007 14. Feb 2003 22:10

das gucke ich mir mal an, danke :)

jbg 14. Feb 2003 22:22

Bedenke, dass die Unit als allererste im Projektquellcode eingebunden wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:08 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz