Delphi-PRAXiS
Seite 2 von 2     12   

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 16. Jul 2015 22:57

AW: Maßnahmen zum Speicherverbrauch minimieren
 
In dem Projekt male ich keine Striche.

Aber egal. Ich habe verstanden, dass
Delphi-Quellcode:
StringA := 'XXX';
StringB := StringA;
einmal Speicher belegt und
Delphi-Quellcode:
StringA := 'XXX';
StringB := 'XXX';
zweimal.

Was bei meinem Projekt möglicherweise falsch läuft, suche ich dann am WE.
Wird schon klappen... ;-)

TiGü 17. Jul 2015 08:09

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Irgendwie fehlt mir gerade heute morgen nach nur einen Kaffee die Fantasie, um zu ergrübeln, was man mit einer derartigen hohen Anzahl von Objekten machen möchte.
Bei derart hohen Speicherauslastungen hätte ich spontan auf Bild- und/oder Videoverarbeitung getippt, aber das ist wohl nicht der Fall, oder?

BUG 17. Jul 2015 09:06

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Wenn ich das richtig verstanden haben, möchte Stahli später eine Verdrängung implementieren, aber möchte trotzdem erstmal den Speicherbedarf verringern. Das finde ich legitim.

Mavarik 17. Jul 2015 09:12

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von BUG (Beitrag 1308957)
Zitat:

Zitat von Sir Rufo
Und du bastelst da nochmal ein Interface drum herum und das anscheinend auch noch falsch ...
Warum sollte ich mir etwas anschauen, wo du bunte Striche malst?

Da ist aber jemand angefressen :mrgreen:

ne er hat ja Recht. Das ist wieder so ein Glaskugel Thread...

42!

Union 17. Jul 2015 09:17

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Auch ich würde gerne helfen. Ist aber schwierig ohne ein entsprechendes Testprojekt.

Mavarik 17. Jul 2015 09:42

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von Union (Beitrag 1308983)
Auch ich würde gerne helfen. Ist aber schwierig ohne ein entsprechendes Testprojekt.

:lol: Klasse EMBT Antwort...

Union 17. Jul 2015 11:08

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von Mavarik (Beitrag 1308989)
Zitat:

Zitat von Union (Beitrag 1308983)
Auch ich würde gerne helfen. Ist aber schwierig ohne ein entsprechendes Testprojekt.

:lol: Klasse EMBT Antwort...

Ja, ich finde "42" und "Glaskugel" auch viel besser. Aber das ist ja Dein Patent ;)

stahli 17. Jul 2015 12:50

AW: Maßnahmen zum Speicherverbrauch minimieren
 
@BUG

Wenn Du mit "Verdrängung" meinst, dass Daten auch ausgelagert werden können (ORM/Datenbank) dann stimmt das genau.

@TiGü

Wie Bug schrieb sehe ich das eher als abstraktes Thema an. WENN man viele Daten in Objekten halten will ist es nicht schlecht, die Datenspeicherung etwas zu optimieren.
Das trifft auch zu, wenn man die Möglichkeit vorsieht, Datenmengen in eine Datenbank auszulagern.
Platz sparen ist generell schon sinnvoll, abgesehen vielleicht, wenn man weiß, dass das eigene Projekt ohnehin nur wenig Speicher verbraucht.
Ich dachte, es gäbe hier Tipps wie: bestimmte Linkeroptionen ausschalten, RTTI deaktivieren, auf Generics verzichten usw.

@Mavarik
!48

@Union
Das Projekt kennst Du ja, nur nicht den aktuellen Quelltext.
Meine Kontaktkanäle wären noch offen...

@Sir Rufo
Da ich
Delphi-Quellcode:
fName: String
durch
Delphi-Quellcode:
fNameIntf: IInterfaceMitNamenEigenschaft
ersetzt habe bin ich davon ausgegangen, dass der Speicherverbrauch deutlich zurückgeht, da es dann nur noch wenige Objekte gäbe, die die eigentlichen Namen verwalten. Auf diese würden nur noch Pointer zeigen.
Dass das Gegenteil rauskam hat mich verwundert. Aber gestern war es mir dann schon zu spät für weitere Untersuchungen.
Die Namen werden von dem benamten Objekt (Interface) über eine Funktion bereitgestellt:
Delphi-Quellcode:
S := MyNamedIntf.Name;
und dann lokal weiter verarbeitet.
Eigentlich sollte der String-Speicher dann ja wieder freigegeben werden, wenn der lokale Scope verlassen wird.
Ich werde heute Abend Dein Demoprojekt mal umbauen (TNameObject + INameInterface) und damit testen.
Ich will ja auch verstehen, wie das zusammenhängt. Bisher hatte ich noch keinen Bedarf an solchen Optimierungen und daher keine entsprechenden Kenntnisse.

Ich melde mich dann wieder...

idefix2 17. Jul 2015 17:54

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Wie lange können deine Namen maximal werden, wie lange sind sie im Durchschnitt, und wieviele verschiedene Namen gibt es?
Von den Fragen hängt wohl ab, in welcher Richtung da Optimierungen zielführend sein können.

stahli 18. Jul 2015 09:18

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Liste der Anhänge anzeigen (Anzahl: 2)
So, mal ein Testprojekt (XE3-Projekt + EXE) anbei.

Man kann erst mal mehrere Namen-Objekte erzeugen und dann mehrere Business-Objekte (bzw. Interfaces), denen dann Namen zugewiesen werden.

Den Zuweisungsmodus kann man auswählen. Man kann die Stringvariable übergeben oder das Namenobjekt oder einen neuen Text.
Jeden Modus einmal mit const- und var-Parameter.

Das Zuweisen eines neuen Textes erzeugt erwartungsgemäß einen höheren Speicherbedarf.
Stringreferenz und Interfacereferenz sind gleichermaßen platzsparend.
Ob var- oder const-Parameter spielt keine Rolle.

Jetzt werde ich mein Projekt nochmal entsprechend überarbeiten.

Sir Rufo 18. Jul 2015 10:17

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Eigentlich brauchst du in deinem Projekt ja gar nicht viel ändern.

Du musst nur in dem Name-Setter eine Logik einbauen, die den String cached, bzw. den String aus dem Cache verwendet.

Dann bleibt deine Anwendung wie sie ist und trotzdem verbrennt die keinen Speicher.

So könnte dann ein StringCache aussehen
Delphi-Quellcode:
unit Common.StringCache;

interface

uses
  System.Generics.Collections,
  System.Generics.Defaults,
  System.SysUtils;

type
  IStringCache = interface
    [ '{BDD29CD1-319F-43AF-B0EE-1C7AE5E66AEC}' ]
    function Get( const AValue: string ): string;
    procedure Reset( var AValue: string );
  end;

  TStringCache = class( TInterfacedObject, IStringCache )
  private
    FLock: TObject;
    FDict: TDictionary<string, string>;
    function Get( const AValue: string ): string;
    procedure Reset( var AValue: string );
  public
    constructor Create;
    destructor Destroy; override;
  private
    class var _Default: IStringCache;
    class constructor Create;
  public
    class function Default: IStringCache;
  end;

implementation

{ TStringCache }

constructor TStringCache.Create;
begin
  FLock := TObject.Create;
  inherited Create;
  FDict := TDictionary<string, string>.Create;
end;

class constructor TStringCache.Create;
begin
  TStringCache._Default := TStringCache.Create;
end;

class function TStringCache.Default: IStringCache;
begin
  Result := _Default;
end;

destructor TStringCache.Destroy;
begin
  FreeAndNil( FDict );
  FreeAndNil( FLock );
  inherited;
end;

function TStringCache.Get( const AValue: string ): string;
begin
  TMonitor.Enter( FLock );
  try
    if not FDict.TryGetValue( AValue, Result ) then
    begin
      FDict.Add( AValue, AValue );
      Exit( AValue );
    end;
  finally
    TMonitor.Exit( FLock );
  end;
end;

procedure TStringCache.Reset( var AValue: string );
begin
  AValue := Get( AValue );
end;

end.
und das sind die Änderungen in deinem Beispiel-Projekt
Delphi-Quellcode:
uses
  Common.StringCache;

{ TNameObject }

procedure TNameObject.set_Name( const Value: string );
begin
  // fName := Value;
  fName := TStringCache.Default.Get( Value );
end;

procedure TNameObject.set_Name_( Value: string );
begin
  // fName := Value;
  fName := TStringCache.Default.Get( Value );
end;

{ TBusinessObjectString }

procedure TBusinessObjectString.set_Name( const Value: string );
begin
  // fName := Value;
  fName := TStringCache.Default.Get( Value );
end;

procedure TBusinessObjectString.set_Name_( Value: string );
begin
  // fName := Value;
  fName := TStringCache.Default.Get( Value );
end;
und schwupps ist der Speicherverbrauch überall gleich. ;)

stahli 18. Jul 2015 11:22

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Im Grunde stimmt das. Ich werde aber aus anderen Gründen aber die Interface-Lösung nutzen, da die einfachen Strings nicht reichen.

Meine Erkenntnisse:

- Das Zuweisen von String-Vatiablen zueinander verbraucht nur einmal Speicherplatz.
- Der Speicherplatz wird freigegeben, wenn es keine Referenzen mehr darauf gibt.
- (Die Speicherverwaltung von Strings entspricht heute quasi der von Interfaces)
- Zuweisung von Texten
Delphi-Quellcode:
StringA := 'Text'
und
Delphi-Quellcode:
StringB := 'Text'
belegt zwei mal Speicherplatz

Zunächst wusste ich von der Speicheroptimierung gar nichts.
Dann hatte ich die Hilfe so verstanden, dass "gleiche Texte" speichertechnisch referenziert werden (also der letzte Anstrich auch nur einmal Speicher belegt - was durch den Einsatz eines Dictionarys grundsätzlich ja auch möglich wäre, wie der Sir zeigt).
Jetzt liege ich wohl zwischen beiden Extremen richtig. :-)


Dann hielt ich es bezüglich der Speicherverwaltung für möglich, dass es einen Unterschied machen könnte, ob Strings als Funktionsparameter als var oder const übergeben werden. Das ist aber scheinbar nicht so.


Die Hilfe ist zwar bezüglich der Strings sehr umfangreich. Ich kann trotzdem nicht alles richtig nachvollziehen.
Kann aber durchaus an mir liegen. :oops:


Mal noch etwas anderes: Die Fragen
- Wieviel Speicherplatz habe ich noch, bis ein OutOfMemory kommt?
- Wieviel Speicherverbrauch meiner Anwendung würde der TaskManager ausgeben?
lassen sich nicht beantworten - oder?
Ich habe ein paar Diskussionen gefunden, bin aber nicht ganz schlau draus geworden - außer, dass es wohl nicht geht.

Mavarik 18. Jul 2015 12:26

AW: Maßnahmen zum Speicherverbrauch minimieren
 
hmm hab ich jetzt was falsch verstanden?

10.000.000 Namecount & 10.000.000 BusinessCount sagt dein Programm

1. Test: (Name 6611715)
2. Test: (Name 4062733)
3. Test: (Name 2331856)

???

stahli 18. Jul 2015 12:36

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Sorry, das hätte ich noch erklären müssen.

Durch die Auswahl in der RadioGroupBusiness werden entsprechend viele Businessobjekte erzeugt und die Namen jeweils zufällig zugewiesen.
Dann werden die Namen ausgelesen (damit ich auch mal einen Zugriff darauf habe) und einer Stringvariablen zugewiesen.
Der letzte (zufällige) Wert wird dann einfach angezeigt.

Da ist also nicht weiter aussagekräftig und soll lediglich die Benutzung der Strings simulieren.
Durch Änderung des Wertes erkennt man außerdem, dass das Programm zumindest etwas ausgeführt hat.

freimatz 23. Jul 2015 12:51

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von stahli (Beitrag 1309031)
WENN man viele Daten in Objekten halten will ist es nicht schlecht, die Datenspeicherung etwas zu optimieren.

Nein. Nein. Nein.
http://ccd.ralfw.domainfactory-kunde..._Optimierungen

Umgekehrt: es ist schlecht viele Daten in Objekten halten zu wollen.

Natürlich ist es gut nichts überflüssiges im Speicher zu haben. Jede weitere Massnahmen macht den Code nur schwerer Lesbar und verhindert weitere Optimierungen.

idefix2 23. Jul 2015 15:36

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Das ist in dieser Pauschalierung nicht richtig und von den Autoren wohl auch nicht so gemeint.
Optimierungen, mit denen Daten "künstlich" zusammengepresst werden, um Speicherplatz zu sparen, sind meistens schlecht, und meistens gibt es bessere Möglichkeiten zur Optimierung, die auf einer anderen Ebene laufen, das ist richtig (wenn es in einer Property mit Getter und Setter sauber gekapselt ist, muss aber nicht einmal das schlecht sein).

Datenstrukturen so zu wählen, dass nicht völlig unnötig Speicherplatz verbraten wird, kann generell nicht schaden.

Zitat:

Zitat von freimatz (Beitrag 1309637)
Umgekehrt: es ist schlecht viele Daten in Objekten halten zu wollen.

Klar. Es ist viel besser, die Daten auf der Platte zu lassen und dort zu suchen. Soll der Anwender doch warten, dafür hat er ein "besseres" Programm.

Mavarik 23. Jul 2015 15:51

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von idefix2 (Beitrag 1309661)
Das ist in dieser Pauschalierung nicht richtig und von den Autoren wohl auch nicht so gemeint

Das sehe ich auch so... Abgesehen davon halte ich das für groben quatsch... Leider wird viel zu wenig optimiert, daher brauchen wir ja mittlerweile SSD und 3,6 GHz.

Zitat:

Zitat von idefix2 (Beitrag 1309661)
Zitat:

Zitat von freimatz (Beitrag 1309637)
Umgekehrt: es ist schlecht viele Daten in Objekten halten zu wollen.

Klar. Es ist viel besser, die Daten auf der Platte zu lassen und dort zu suchen. Soll der Anwender doch warten, dafür hat er ein "besseres" Programm.

Eben... Wofür habe ich 64GB in meinem Rechner, wenn meine Software möglichst mit 640KB versucht aus zu kommen und jeden Mist von der Platte nachlädt...

Warum soll ich für 400MB ne komplizierte SQXY Datenbank an legen, wenn ich am Anfang einfach 1GB Speicher reserviere und alle Daten in einem Rutsch in einen Puffer laden kann...(Nicht auf einem Mobilen Device) :stupid:

Mavarik

freimatz 23. Jul 2015 15:56

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Welche Pauschalierung meinst du? Allgemeine Regeln müssen immer pauschal sein.
Bei all dem was ich hier so rauslese, wäre es aber schon gut die Regel zu beachten.
Naürlich ist es nicht gut, wenn der Anwender warten muss. Aber ein Programm das wegen zu wenig Speicher abstürzt ist noch viel schlechter.
Und die Zeit um mit viel Aufwand vielleicht 10% rauszuholen ist besser in eine besser Logik besser investiert.
Was anderes sind Fälle in denen es um klar begrenzte Datenhaltung geht wie z.B. in der Messtechnik. Wenn es um Businessobjekte geht, trifft das m.E. nicht zu.

BUG 23. Jul 2015 16:03

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von Mavarik (Beitrag 1309663)
Warum soll ich für 400MB ne komplizierte SQXY Datenbank an legen, wenn ich am Anfang einfach 1GB Speicher reserviere und alle Daten in einem Rutsch in einen Puffer laden kann...

Die Entscheidung für oder gegen Datenbank ist nochmal etwas anderes, da die zusätzliche Garantien liefert als einfach nur irgendwie Zugriff auf Daten.
Nicht zu vergessen, dass man mit einer relationalen Datenbank unzähligen Personenjahren an Optimierung mit nutzt.

stahli 23. Jul 2015 16:09

AW: Maßnahmen zum Speicherverbrauch minimieren
 
@freimatz

Ja, an der Überlegung ist schon was dran. Man muss halt abwägen, was im Einzelfall wichtiger ist. U.U. können 10% Speicherersparnis so wichtig sein, dass man dafür mehrere Wochen Arbeit für investieren würde.

Deine erste Aussage war zu unkonkret und der konnte ich auch nicht folgen.


Jetzt will ich mich nochmal selbst zitieren:
Zitat:

- Wieviel Speicherplatz habe ich noch, bis ein OutOfMemory kommt?
- Wieviel Speicherverbrauch meiner Anwendung würde der TaskManager ausgeben?
Die Fragen wären wichtig, um Abstürze zu vermeiden. So könnte das Programm entscheiden wann es anfangen muss, Daten auszulagern.
Aber offenbar gibt es da wohl keine klare Antwort drauf...

freimatz 23. Jul 2015 16:31

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Die Frage nach dem Speicher wurde gerne verdrängt. Warum es wichtig ist, was der Taskmanager anzeigt erschließt sich mir nicht. (Außer das manche Leute meinen man könne da auf Memory-Leaks schließen)
Die Frage vieviel Speicherplatz habe ich noch finde ich schon sehr wichtig. Ich glaube da aber nicht dass es keine Antwort darauf gibt, auch wenn ich sie leider auch nicht weiß.

Um den verbrauchten Speicher festzustellen benutzen wir
Delphi-Quellcode:
class function TMemoryManager.GetApplicationMemory(): Int64;
var
  memoryState: TMemoryManagerState;
  blockState : TSmallBlockTypeState;
begin
  GetMemoryManagerState(memoryState);
  with memoryState do begin
    Result := TotalAllocatedMediumBlockSize + TotalAllocatedLargeBlockSize;
    for blockState in SmallBlockTypeStates do
      Inc(Result, blockState.AllocatedBlockCount * blockState.UseableBlockSize);
  end;
end;
Wieviel Speicher noch frei ist, sollte man doch von Windows erfahren können. Bin jetzt zu faul zum googeln. :-D

Sir Rufo 23. Jul 2015 16:34

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Hier ging es aber darum, dass eine Handvoll Objekte den Speicher mit Meta-Informationen zugemüllt haben.

Vermutlich haben diese Meta-Informationen mehr Speicher verbraucht als die Nutzdaten. Das ist in meinen Augen keine Optimierung.

Wenn ich tonnenweise Speicherlecks produzieren würde, dann ist das Beseitigen auch keine Optimierung, sondern ich mache es erst dann richtig. Optimierungen fangen da an, wo man mit richtig fertig ist.

Make it work, then make it fast (and/or smart).

stahli 23. Jul 2015 16:48

AW: Maßnahmen zum Speicherverbrauch minimieren
 
@freimatz

Memory-Leaks habe ich nicht (siehe #15).

Der Taskmanager bietet einen Hinweis, wie viel Speicher die Anwendung aktuell insgesamt verbraucht. Das wäre schon mal ein Anhaltspunkt.
Ich werde demnächst mal Deine Funktion testen.

Zitat:

Zitat von freimatz (Beitrag 1309669)
Wieviel Speicher noch frei ist, sollte man doch von Windows erfahren können. Bin jetzt zu faul zum googeln. :-D

Ich habe dazu nichts gefunden, versuche es aber später nochmal.


@Sir Rufo

Die Strings sind Nutzdaten. Als Müll würde ich die eigentlich nicht bezeichnen wollen. ;-)

BUG 23. Jul 2015 16:54

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Die Frage nach dem freien Speicher ist kompliziert, da sich die Rahmenbedingungen ständig ändern können. Das fängt schon in dem Moment an, in dem jemand im Prozess, aber außerhalb der Kontrolle deines Frameworks anfängt, Speicher zu allozieren (zum Beispiel in einer DLL).

Man kann dem Framework ein konfigurierbares Limit geben, das man selbst überwacht; wenn diese Grenze bei einer Allokation überschritten würde, muss es vorher Objekte freigeben.
Das sollte man wohl auch machen, wenn eine Allokation fehlschlägt(OutOfMemory). Dabei sollte man es vermeiden, beim Freigeben Objekte anlegen zu müssen :stupid:
Außerdem kann man in diesem Moment das Limit heruntersetzen.

Sir Rufo 23. Jul 2015 16:58

AW: Maßnahmen zum Speicherverbrauch minimieren
 
Zitat:

Zitat von stahli (Beitrag 1309673)
@Sir Rufo

Die Strings sind Nutzdaten. Als Müll würde ich die eigentlich nicht bezeichnen wollen. ;-)

Die Strings, die die Eigenschaften beschreiben sind Meta-Informationen. Die Werte der Eigenschaften sind die Nutzdaten.

Und als Müll habe ich die nicht bezeichnet, sondern nur, dass diese Meta-Informationen den Speicher vollgemüllt haben. Um die Schuhgröße zu speichern hast du 4 Byte Nutzdaten (Double) und 20+ Byte Meta-Informationen (UnicodeString) verbraten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:03 Uhr.
Seite 2 von 2     12   

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