![]() |
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. |
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. |
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...? |
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 :| |
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 |
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 |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
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:
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.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; 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 : ![]() cu Ha-Jö cu Ha-Jö |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Zitat:
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
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 |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Daher ja STRING[5] oder was auch immer... Und der braucht auch nur 6 Byte |
AW: Maßnahmen zum Speicherverbrauch minimieren
JEDER Shortstring wird mit 256 Byte alloziiert. BELEGT werden davon dann nur 6, das ist richtig. Eine sehr schöne Erläuterung findet sich
![]() ![]() |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Zitat:
Wenn ich einen String[80] definiere aber immer nur "ABC" rein schreibe ist das natürlich quatsch... Dann ist der Ansistring besser... Aber spätestens wenn ich die AnsiStrings in einem Record habe, klappen schon keine Zuweisungen des Records mehr... keine Moves, keine Blockwrites... (Oder für die "neuen": kein Streamwrite in einem Rutsch) |
AW: Maßnahmen zum Speicherverbrauch minimieren
Mit dem Umweg über einen eigenen Typen geht es tatsächlich, da hast Du vollkommen Recht. Nur muss man dann für jede mögliche Maximallänge eine Typdefinition erstellen - um das gleiche Ergebnis zu erreichen wie mit einem (P)Ansistring. Ich denke, ein Lazy-Loading Pattern in Verbindung mit einem eigenen GC sollte mehr Erfolg versprechen.
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für Eure Hilfe!
Ich bin auch etwas überrascht, dass der Speicherbedarf so hoch ist. Mit etwas einfacheren Objekten konnte ich 3-4 Mio Stück erzeugen. Wenn allerdings jedes Objekt wieder n Unterobjekte verwaltet, dann reduziert das natürlich die Anzahl der Hauptobjekte. Mit Unterobjekten sind dann sowohl die Verwaltungsobjekte gemeint, die Businessobjektreferenzen verwalten, als auch die benötigten untergeordneten Businessobjekte selbst. Businessobjekte werden von einer Factory erzeugt und zentral verwaltet. Die Factory gibt dann nur Interfaces auf diese Objekte heraus. Eine Objektinstanz wird nur neu erstellt, wenn es noch keine entsprechende gibt. Sonst wird das existierende Objekt wiederverwendet. Memoryleaks habe ich nicht (bis auf 4 kleine Indy-Klassen - scheint wohl ein Bug zu sein, der aber jetzt hier nicht wirklich relevant ist). Anbei mal ein Screenshot eines veralteten MemLogs. Die StringLists habe ich inzwischen schon entfernt. Das erhöhte die Objektanzahl schon mal von 70T auf knapp 100T. Dass die RTTI-Entfernung nur eine einmalige Auswirkung hätte ist mir klar. Ich weiß nur nicht, wie viel das ausmacht und was es noch für Optionen gäbe. Die Info mit dem ShortString ist hilfreich. So weit war ich noch nicht vorgedrungen. In der Hilfe sah es irgendwie so aus, als wären ShortString und WideString identisch. AnsiString für die Namenbezeichner dürfte aber sicher was bringen, denke ich. Ich werde also mal Stück für Stück schauen, was ich an meinen Klassen optimieren kann. So einen richtigen Brüller, der hier mal schnell zu einer großen Entlastung führt, habt Ihr offenbar auch nicht zur Hand. Dass mein Manager später den Speicherverbrauch überwachen und Objektdaten wegschreiben und die Objekte wieder auflösen muss ist klar. Aber um so optimierter die Objekte verwaltet werden um so mehr können im Speicher gehalten werden und um so performanter kann das Ganze laufen. Ich werde also mal die Details prüfen, wie String zu AnsiString oder Listenobjekte erst instanziieren, wenn ein Unterobjekt hinzugefügt werden soll etc... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Kann es sein, dass Du dich mit deinen Zeigerliste ein wenig zu Tode verwaltest? Wenn Du mal verrätst was Du speichern willst, können wir sicherlich besser helfen... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Das schaue ich mir jetzt mal an...
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
5,2 KB , sonst wirds 1 TB Ram |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Wäre es nicht denkbar, das Klassen an sich mehr Speicherplatz verbraten, als z.B. Records? Davon unabhängig solltest Du einfach mal messen, wie groß ein Businessobjekt inklusive aller Unterobjekte ist. Dazu kannst Du dir ja einfach eine Funktion 'Size' für alle Klassen implementieren:
Delphi-Quellcode:
Dann hast Du schon einmal den Nettoverbrauch an Daten. Das solltest Du in der Factory machen, d.h. die Factory führt darüber Buch, wie viel Bytes es bisher produziert hat.
Function TMyObject.Size : Integer;
begin Result := SizeOf(FMyDouble)+StringSize(FMyString); For item in FMyObjectList do inc(Result, item.Size); end; Wäre doch mal interessant, ob wirklich die Objekte das Problem sind, oder nicht etwas anderes. Wie sehen deine Objekte denn in etwa aus? Müssen es Namen (String) sein, um ein Objekt zu identifizieren? Tut es ein integer nicht auch? |
AW: Maßnahmen zum Speicherverbrauch minimieren
Ich habe gestern einfach mal String durch AnsiString ersetzt.
Nach Studium der Hilfe ![]() war zu erwarten, dass es nicht sehr viel ausmachen wird. Und so ist es auch. Statt 92539 Hauptobjekten konnte ich 97059 erzeugen. Wie bereits beschrieben, sind das die Hauptobjekte, denen diverse Eigenschaften, Listen und Referenzzeiger zugeordnet sind. Wirkliche Objekte werden viel mehr erzeugt. Auf die Namen kann ich nicht verzichten. Aber ich könnte einen platzsparendere Stringtyp wählen. Ich weiß nur noch nicht welchen. Ich habe gestern mal versucht, mit AQTime Pro den Speicherbedarf einer Methode zu profilen, in der eines meiner Hauptobjekte erzeugt wird. Im Gegensatz zu dem Performance-Profile ist das aber beim Allocation-Profiler scheinbar so nicht möglich. Zumindest habe ich das gestern nicht hingekriegt. Also werde ich das mal (wie von Dejan Vu vorgeschlagen) von meiner Factory protokollieren lassen oder das Projekt entfrachten und nur ein Mainobject erzeugen und dieses mit AQTime analysieren. Über eine schrittweises Debuggen ist mir erst mal nichts falsches aufgefallen. Es sind halt recht viele Untereigenschaften und ich werde schauen müssen, was ich dort optimieren kann. Ich werde mich also mal weiter Stück für Stück voran tasten... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Ich habe da so eine vage Vermutung, was deinen immensen Speicherbedarf verursacht.
Kannst du mal das Interface von so einem BO zeigen und wie du auf eine Eigenschaft zugreifst? Ich vermute nämlich, dass du für jede BO Instanz die Eigenschafts-Namen als String im Speicher hast ... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Worauf willst Du raus?
Ich habe z.B.
Delphi-Quellcode:
Die Klasse hält dann natürlich noch ein fName: String bzw. ein Objekt, das einen String verwaltet.
IMyInf = interface
... property Name: string read get_Name write set_Name ... Bei Bedarf durchsuche ich eine Liste nach einem Interface mit einem bestimmten Namen. Wenn das einmal gefunden ist arbeite ich nur noch direkt mit dem Interface. Beziehungen zwischen Objekten/Interfaces werden nicht über Namen-Strings abgebildet. Ich kann gern mal einen Auszug raussuchen, aber es wäre gut zu wissen, wo Du ein Problem vermutest... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Ich vermute, dass genau diese Strings, die den Namen für was auch immer definieren, dir den Speicher vollmüllen.
Das kann ich aber erst sehen, wenn ich sehe, wie du denn mit diesen Namen in deinem BO umgehst |
AW: Maßnahmen zum Speicherverbrauch minimieren
Im Prinzip: Hast du Strings (außer einem eindeutigem Namen), die du für jedes BO anlegst?
SirRufo will vermutlich auf so etwas wie Eigenschafts/Spalten-Namen hinaus, die bei vielen Objekten gleich wären. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Wie hoch ist denn der Speicherverbrauch (z.B. auch einfach im Taskmanager, muss nicht so genau sein), wenn du die Out-Of-Memory Exception bekommst?
Wir hatten das gleiche Problem und haben daraufhin auf 64-Bit umgestellt, da es bei unserer Anwendung mit Speicher sparen nicht gereicht hätte. Dort konnte man aber einen Riesenunterschied zu dem Out-Of-Memory der Delphi IDE sehen: Bei uns kam der Speicherverbrauch auf ca. 1,7-1,8 GiB hoch bevor es zum Problem kam. Bei der Delphi IDE hingegen kommt (vermutlich durch ungünstiges Speichermanagement?) der Fehler schon bei ca. 1 GiB. Wodurch wir Speicher sparen konnten war z.B. die Verwendung von TDictionary statt TStringList für die Zuordnung zwischen Strings und anderen Daten, da dadurch nur noch ein Hash im Speicher bleibt statt des ganzen Strings. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
![]() |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Bei Video2Brain gibt es ein gutes Tutorial zu Datenstrukturen: ![]() Ist so ein kleiner 3h-Ersatz für ein 3jähriges Studium. ;-) Ich fand es interessant, wenn auch nicht alles ganz neu war. @jaenicke Aber ansonsten scheint Euer Problem zu meinem zu passen. Ich muss die Speichergrößen nochmal zusammentragen. Mit und ohne Delphi sowie als Debug und Release. Mache ich mal heute Abend. Unter 64 Bit gab es die Probleme natürlich nicht. Ich hatte da mal ein paar Mio Mainobjekte versucht. Aber ich will natürlich dennoch das Ganze möglichst optimieren. @Sir + Bug Ja, die Richtung kommt schon hin. Eigenschaften von Objekten werden mit Namen bezeichnet (z.B. "FirstName"). Dem wird dann ein Wert zugeordnet (z.B. "Sir"). Wenn es viele Objekte gibt, die eine Eigenschaft "FirstName" haben wird der String häufig verwendet. Nun hatte ich aber in der Hilfe ( ![]() Ich hatte auch schon überlegt (genauer gesagt ist das auch aus einem Projektinternen Grund ernsthafte Absicht ;-)), in den Eigenschaften statt auf einen Namen-String auf ein Namen-Objekt zu verweisen, das einen String enthält. Dann würden nur noch Pointer verbraucht werden und das Namensobjekt könnte beliebig oft referenziert werden. Wenn die vorherige Annahme mit den String-Referenzen stimmt, würde das aber am Gesamtverbrauch nicht mehr viel ausmachen. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
![]() Ich halte es für besser, einen Stringimplementierung zu benutzen, die sicherstellt, dass Strings mit gleichem Inhalt ihren Speicher teilen. Niemand garantiert, das Strings in Delphi für immer Referenz-gezählt bleiben. |
AW: Maßnahmen zum Speicherverbrauch minimieren
@stahli
Deine Annahme mit der String-Speicherverwaltung ist leider nicht korrekt, wie dir diese kleine Anwendung zeigen wird, wenn du dabei den Task-Manager beobachtest. Hier wird auch immer der gleiche String-Wert zugewiesen, aber auf unterschiedliche Art und Weise mit eben einer unterschiedlichen Speicherauslastung, obwohl effektiv gesehen in allen Instanzen, der gleiche Wert enthalten ist.
Delphi-Quellcode:
unit Form.MainForm;
interface uses System.Generics.Collections, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TFoo = class private FValue: string; public property Value: string read FValue write FValue; end; TForm1 = class( TForm ) Timer1: TTimer; TimerEnabledCheckBox: TCheckBox; FillCachedValuePropertyCheckBox: TCheckBox; procedure TimerEnabledCheckBoxClick( Sender: TObject ); procedure Timer1Timer( Sender: TObject ); procedure FormShow( Sender: TObject ); procedure FormActivate( Sender: TObject ); procedure FillCachedValuePropertyCheckBoxClick( Sender: TObject ); private FValue: string; FFooList: TObjectList<TFoo>; function GenerateValue: string; function GetValue: string; procedure PresentValues; public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var Form1: TForm1; implementation uses System.StrUtils; {$R *.dfm} { TForm1 } procedure TForm1.AfterConstruction; begin inherited; FFooList := TObjectList<TFoo>.Create( True ); FValue := GenerateValue; end; procedure TForm1.BeforeDestruction; begin FreeAndNil( FFooList ); inherited; end; procedure TForm1.TimerEnabledCheckBoxClick( Sender: TObject ); begin Timer1.Enabled := TimerEnabledCheckBox.Checked; end; procedure TForm1.FillCachedValuePropertyCheckBoxClick( Sender: TObject ); begin FFooList.Clear; PresentValues; end; procedure TForm1.FormActivate( Sender: TObject ); begin PresentValues; end; procedure TForm1.FormShow( Sender: TObject ); begin PresentValues; end; function TForm1.GenerateValue: string; begin Result := DupeString( 'Test', 1000 ); end; function TForm1.GetValue: string; begin if FillCachedValuePropertyCheckBox.Checked then Result := FValue else Result := GenerateValue; end; procedure TForm1.PresentValues; begin TimerEnabledCheckBox.Checked := Timer1.Enabled; TimerEnabledCheckBox.Caption := string.Format( 'FFooList.Count = %d', [ FFooList.Count ] ); end; procedure TForm1.Timer1Timer( Sender: TObject ); var LFoo: TFoo; LIdx: Integer; begin for LIdx := 1 to 100 do begin LFoo := TFoo.Create; try LFoo.Value := GetValue; FFooList.Add( LFoo ); LFoo := nil; finally LFoo.Free; end; end; PresentValues; end; end. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Dann wäre das letztlich ein eindeutiger Schlüssel bzw. Index für einen bestimmten Eintrag - oder?
Ansonsten würden Hashkollisionen möglich sein oder in der Hashtabelle viele Plätze unbelegt bleiben müssen. Kannst Du Euren Ansatz noch etwas erklären? |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Ein Dictionary unterteilt die Key-Menge in Buckets, wo alle Elemente hineinkommen, die den gleichen Hashwert haben und such dann nur noch in diesem Bucket nach dem passenden. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Naja, der Fall ist etwas speziell, in dem Fall war eine Hashfunktion machbar, weil die Strings bestimmte Bedingungen erfüllen. Teile davon konnten in die dahinterliegenden Objekte zusammengefasst werden (stell es dir wie einen Index vor), und bestimmte Teile sind ansonsten eindeutig.
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
|
AW: Maßnahmen zum Speicherverbrauch minimieren
Aaalsooo...
Unter 32bit habe ich mal 4 Varianten versucht, bis Out of Memory kam: Debug, IDE, 97.059, 1.946,2 MB Debug, EXE, 97.125, 1.947,8 MB Release, IDE, 97.498, 1.955,0 MB Release, EXE, 97.498, 1.955,2 MB Also ob Debug oder Release bzw. unter IDE-Kontrolle oder nicht spielt keine Rolle. Unter 64bit (Debug, IDE) habe ich mal 600.000 Mainobjekte erzeugt. Bei ca. 5GB hat Windows scheinbar immer Daten ausgelagert und dann wieder weitere Objekte erzeugt. Keine Ahnung, was da genau passiert. Zumindest sollte man den Speicherverbrauch wohl nicht so hoch treiben, da die Anwendung sonst ausgebremst wird. (Alles nur mein erster Eindruck.) Dann bin ich zurück auf 32bit und habe die gleichen Strings durch Referenzen auf existierende Interfaces ersetzt und dachte, das würde eine deutlich höhere Anzahl von MainObjekten ermöglichen. Das Gegenteil war der Fall. Es waren nur noch 92.539!? Kann sein, dass es heute zu spät für mich ist. Das schaue ich mir am WE noch näher an. Aber ich habe mir auch mal die gesamten Datenobjekte ausgeben lassen 92.480 Mainobjekte -> 1.942.058 Gesamtobjekte Die Mainobjekte haben also durchschnittlich 20 Unterobjekte und insgesamt sind es fast 2Mio. Das sind also schon ein paar, aber die Speicherbedarfsreduzierung bleibt auf jeden Fall ein Ziel von mir. Dann bin ich zurück zu den Strings von vorher (alte Sicherung verwendet). Die Objekte blieben bei 92540->1943318 obwohl es am Anfang ja 97.000 waren. Nach einem PC-Neustart waren es noch weniger: 91348->1918214 Also die Gründe für diese Schwankungen kann ich mir nicht erklären. Vielleicht muss man einfach damit leben. Warum die Änderung auf Objektreferenzen statt den Strings nichts brachte oder sogar kontraproduktiv war, ist mir rätselhaft. (Ein Fehler meinerseits kann hier ggf. allerdings auch möglich sein.) |
AW: Maßnahmen zum Speicherverbrauch minimieren
Tja, ich habe dir gezeigt wie man den Speicherbedarf bei vielen gleichen Strings groß macht oder klein hält.
Da du nicht zeigen möchtest, wie du das konkret umsetzt, wirst du dich darum selber kümmern müssen. Eins kann ich aber sagen: Das mit den Interfaces und den Strings ist von hinten nach vorn dreimal gedreht und einmal hochgeworfen. Ein String wird doch schon quasi wie ein Interface behandelt (siehe mein Beispiel). Und du bastelst da nochmal ein Interface drum herum und das anscheinend auch noch falsch ... |
AW: Maßnahmen zum Speicherverbrauch minimieren
Ein Auszug wir schwierig und durch das ganze Projekt wirst Du Dich nicht wühlen wollen.
Ich nehme mir am WE dafür Zeit. |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
Es geht doch nur um das BO und die Liste mit den Eigenschaften und die Stelle, wo so ein BO erzeugt wird. Da ist der Speicherfresser. Warum sollte ich mir etwas anschauen, wo du bunte Striche malst? |
AW: Maßnahmen zum Speicherverbrauch minimieren
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 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