Delphi-PRAXiS
Seite 1 von 7  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Maßnahmen zum Speicherverbrauch minimieren (https://www.delphipraxis.net/185886-massnahmen-zum-speicherverbrauch-minimieren.html)

stahli 15. Jul 2015 12:02

Maßnahmen zum Speicherverbrauch minimieren
 
Ich entwickle unter XE3 (VCL) ein Projekt, das viele dynamische Objekte mit unterschiedlichen Eigenschaften erzeugt (zum großen Teil verschachtelte Listen als Untereigenschaften).

Listen sind z.B. TList<IMyInterface> und TList<IMyNamedObject> sowie einige TStringLists.
Die NamedObjekte haben eine Eigenschaft Name, die letztlich einen String enthält.

Jedes Businessobjekt hat Listen als Eigenschaften, die wieder unterschiedliche Unterobjekte bzw. Interfaces verwalten.

Aktuell kann ich in einer 32bit-Anwendung unter Debugging knapp 100.000 Businessobjekte erzeugen, bis ich ein out of Memory erhalte.

Welche Maßnahmen wären sinnvoll, den Speicherbedarf der Anwendung runter zu schrauben (sowohl den der Anwendung selbst als auch den der Businessobjekte)?


Aktuell benutze ich einfach String für die Speicherung der Businessobjekt-Namen. Das werde ich auf Ansistring oder Shortstring umstellen können.

Macht es Sinn, auf generische Listen (und TComparer) zu verzichten? Generisch verwende ich nur Listen in der Anwendung und könnte auch auf einfache Listen umstellen (dadurch wären ja nur einige Castings mehr notwendig).

Die neue RTTI brauche ich nicht. Spart das Speicherplatz, wenn man die deaktiviert? Was kann man sonst noch deaktivieren?

Eine Datenbankanbindung und auch eine 64bit-Version ist natürlich auch vorgesehen, dennoch möchte ich den Speicherverbrauch der Anwendung nach Möglichkeit drosseln.

Sir Rufo 15. Jul 2015 12:29

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Die von dir angesprochenen Lösungen verlagern das Problem aber nur ein Stück weiter nach hinten. Dann ist nicht erst bei 100.000 Schluss, sondern bei 150.000 (nur ein geschätztes Beispiel).

Wenn der Speicher-Platz nicht reicht, dann kann man das z.B. mit dem Proxy-Pattern lösen.

Dabei hat man dann nicht mehr das fette BO im SPeicher, sondern eben einen (schmalen) Stellvertreter, der die Daten dann bei Bedarf nachlädt. Möglich wäre auch ein entsprechendes Caching der Daten, die nur für eine bestimmte Zeit im Speicher vorgehalten werden und nach einem Zeitpunkt X wieder aus dem SPeicher geräumt werden. Auch das schafft Platz.

stahli 15. Jul 2015 12:39

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Ja, das habe ich mit meinem letzten Satz anzudeuten versucht (mit Datenbankanbindung meinte ich letztlich einen ORM (bzw. Manager falls ich mich doch noch für NoSQL entscheide), der sich auch um die Lebenszeit der Objekte kümmert).

Mich würde aktuell erst einmal interessieren, welche Maßnahmen man versuchen sollte, um auf 150T oder 200T mögliche Objekte zu kommen.

Z.B. eben durch Ersetzen von String durch AnsiString (wo möglich), rausschmeißen von RTTI oder Generics, oder was sonst noch...?

Der schöne Günther 15. Jul 2015 12:48

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Ich bin da kein Profi, aber Dinge wie RTTI sind doch einmalig vielleicht 5MB Binärcode der drin ist oder nicht. Da wächst doch nichts mit jeder zusätzlich erstellten Instanz.

Auch (dumme Frage, aber trotzdem): Ist dein Speicherverbrauch wirklich so hoch dass man an 32-Bit-Grenzen kommt? Nicht dass du einfach nur ein riesiges Feld allokieren willst und so ein großer Block am Stück ist einfach nicht frei.*


Ansonsten: Das ist doch ähnlich wie wenn jemand Millionen an Zeilen in einer Memo darstellen will und sich dann wundert dass irgendwann nichts mehr geht. Wozu brauchst du hundert tausende von den Dingern gleichzeitig im Speicher? Ich würde als erstes schauen dass man mittels lazy-loading wirklich erst dicke Brocken in den Speicher schaufelt wenn es wirklich so weit ist und darauf achten dass es nicht erst bei Anwendungsende wieder freigegeben wird ;-)


* Oder kümmert sich Windows da mit irgendwelchen schlauen Paging und MMF-Geschichten drum? Mann, Betriebssysteme war eine der langweiligsten Vorlesungen die ich je hatte. Nicht viel behalten :|

hoika 15. Jul 2015 12:56

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Hallo,
die Umstellung auf ShortString bringt wohl gar nichts, wird wohl eher größer:
ein String[50] mit "123" verbraucht mehr Speicher als ein String mit "123".

1.
Ich würde für Tests einfach mal ein BusinessObject mit String und dann mit AnsiString erzeugen,
es nicht freigeben und mit FastMM4 prüfen, wer mehr Speicher verbraucht.

2.
Vielleicht hast du ja ach einfach auch nur ein Speicherleck.

3.
Ausserdem solltest du prüfen, ob du wirklich 100.000 Objekte im Speicher haben musst.

4.
Du könntest auch etwa an deiner Datenstruktur verändern, indem globale Objekte nur einmal geladen werden
und die anderen Objekte direkte Pointer darauf haben.

Unter 32-bit kann man halt "nur" 2 GB Speicher benutzen, mit Tricks 3 GB.


Heiko

HeZa 15. Jul 2015 13:19

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Hallo Stali,

du kannst deine Objekte einmal darauf hin untersuchen, wieviele Varianten einer Klasse benötigt werden. Vielleicht hast du Objekte, die zwar millionenfach referenziert werden, aber von denen es nur 1000 verschiedene Varianten gibt.

Dann brauchst du für so eine Klasse nur tausend Objekte in einem Pool zu erzeugen und holst daraus die Referenz auf die benötigte Variante über eine Funktion/Factory Methode.

Ich versuche mal ein Beispiel:
Du lädst 100.000 Aufträge mit durchschnittlich 100 Positionen, jede Position hat ein Artikel-Objekt (das vielleicht auch noch sehr umfangreich ist). Dann würdest ein simpler Ansatz 10.000.000 Artikel-Objekte erzeugen und den Positionen zuordnen. Es gibt vielleicht aber nur 10.000 verschieden Artikel. Dann könntest du durch den oben beschriebenen Ansatz 9.990.000 Objekte sparen.

Diesen und auch die Vorschläge Sir Rufo findest Du im Buch
Design Patterns: Entwurfsmuster als Elemente wiederverwendbarer objektorientierter Software

hanvas 15. Jul 2015 13:22

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von stahli (Beitrag 1308741)
Mich würde aktuell erst einmal interessieren, welche Maßnahmen man versuchen sollte, um auf 150T oder 200T mögliche Objekte zu kommen.

Z.B. eben durch Ersetzen von String durch AnsiString (wo möglich), rausschmeißen von RTTI oder Generics, oder was sonst noch...?

Zum einen könntest Du nachsehen ob es in deinem Objekt lineare Abhängigkeiten gibt, also Eigenschaften die sich aus anderen Eigenschaften errechnen lassen. Auf diese Eigenschaften könntest Du verzichten.

Dann wäre es eine Überlegung ob Du immer das ganze BO im Speicher halten müsstest oder nur einen bestimmten Teil (sozusagen den Primärindex) dann könntest Du dein BO in mehrere Happen aufteilen die je nach Bedarf geladen werden.
Den Zugriff auf nicht geladene Properties müsstest Du dann natürlich über Methoden implementieren und darauf achten das diese nicht! published sind.

Beispiel (aus dem Handgelenk, aber ich denke das Prinzip wird klar )

Code:

type TBOLazyDataType = record
                          a,b,c,d : Double;
     end;

     pBOLazyDataType = ^TBOLazyDataType;

     TBObject = class(TObject)
     private
      FIdentifier : Integer;
      LazyData : pBOLazyDataType;
     protected
       function getLazyDataByIdentifier ( ident : Integer ) : pBOLazyDataType;
       function getLazyA : Double;
       procedure setLazyA(aValue : Double);
     public
       Constructor Create;    
     property
      Lazy_A : Double
        read getLazyA write SetLazyA;
     end;


...

Constructor TBObject.Create;    
begin
 ...
 LazyData := nil;
end;

function TBObject.getLazyA : Double;
begin
 if not Assigned(LazyA) then
    LazyA := getLazyDataByIdentifier(Identifier);
 result := LazyA.A;
end;

procedure TBObject.setLazyA(aValue : Double);
begin
 if not Assigned(LazyA) then
    LazyA := getLazyDataByIdentifier(Identifier);
 LazyA.A := aValue;
end;
Außerdem könntest Du nach dem gleichen Prinzip überlegen ob bestimmte BOs bestimmte Eigenschaften bzw. Werte teilen, das ist häufig bei hyrarchischen Daten der Fall die dann nur einmal tatsächlich vorkommen müssten und ansonsten über eine Referenz abgebildet werden.

Und letztendlich könntest Du einfach mal nachsehen ob die irgendwo eine Implementierung eines Baumes rumliegen hast der nur Teile seines Datenbestandes im Speicher hält, falls so was nicht auf Deiner Platte ist könntest Du ja mal hier nachsehen : http://synopse.info/fossil/wiki?name=Big+Table

cu Ha-Jö

cu Ha-Jö

Mavarik 15. Jul 2015 14:03

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von hoika (Beitrag 1308744)
die Umstellung auf ShortString bringt wohl gar nichts, wird wohl eher größer:
ein String[50] mit "123" verbraucht mehr Speicher als ein String mit "123".

Wie kommst Du den da rauf?

Union 15. Jul 2015 14:09

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von Mavarik (Beitrag 1308752)
Zitat:

Zitat von hoika (Beitrag 1308744)
die Umstellung auf ShortString bringt wohl gar nichts, wird wohl eher größer:
ein String[50] mit "123" verbraucht mehr Speicher als ein String mit "123".

Wie kommst Du den da rauf?

Vielleicht weil es so ist?
Zitat:

Zitat von DokWiki
While the length of a ShortString can change dynamically, *its memory is a statically allocated 256 bytes*; the first byte stores the length of the string, and the remaining 255 bytes are available for characters


Mavarik 15. Jul 2015 14:12

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von stahli (Beitrag 1308741)
Mich würde aktuell erst einmal interessieren, welche Maßnahmen man versuchen sollte, um auf 150T oder 200T mögliche Objekte zu kommen.

Musst Du die den alle im Speicher halten?

Abgesehen davon ist das doch gar nix oder sind die Objecte so groß?

Sagen wir mal Du nimmst dir 1GB RAM... Und willst da 200.000 Objecte unter bringen...
Dann kann jedes Object 5,2 MB groß sein...

Mavarik


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:13 Uhr.
Seite 1 von 7  1 23     Letzte »    

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