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/)
-   -   Clientdataset Speicherfreigabe (https://www.delphipraxis.net/210718-clientdataset-speicherfreigabe.html)

lxo 1. Jun 2022 16:33

AW: Clientdataset Speicherfreigabe
 
Zitat:

Zitat von Frickler (Beitrag 1506646)
Einfach mal nach "CreateDataSet" die Property "LogChanges" auf false setzen.

Hab ich auch probiert.
Macht keinen Unterschied.

TigerLilly 2. Jun 2022 07:35

AW: Clientdataset Speicherfreigabe
 
ApplyUpdates + Handler für BeforeApplyUpdates sollte das Delta leeren.

CDS schließen und öffnen.

CDS zerstören + neu erzeugen.

Ein anderes MemoryDataSet nehmen.

Das Problem ignorieren - in der Praxis sollte das doch nicht stören, oder was machst du da?

himitsu 2. Jun 2022 08:23

AW: Clientdataset Speicherfreigabe
 
Hab meinen Testcode noch etwas erweitert (erstmal alles, was an Property und Methoden im ClientDataSet zu sehen war, nach dem Delete rein, gesehen es geht und dann schrittweise alles Unnütze wieder raus)
und eine Teillösung gefunden.

Es gibt den Speicher nicht komplett frei, aber zumindesten das Log schein weg zu sein.
(beim nächsten Add und Delete wird kein neuer Speicher hinzugefügt oder freigegeben)
  • LogChanges:=False half nichts
  • CancelUpdates und MergeChangeLog hilft auch nicht
  • aber EmptyDataSet nach oder besser noch anstatt dem While-Delete ist hier die Lösung
    • und es ist sogar um Längen schneller


Delphi-Quellcode:
{$OVERFLOWCHECKS OFF}

uses
  System.StrUtils, Data.DB, Datasnap.DBClient;

procedure TForm8.FormCreate(Sender: TObject);
var
  CDS: TClientDataSet;
  Mem: UInt64;
procedure ShowState;
  var
    GStatus: TMemoryStatusEx;
    MMState: TMemoryManagerState;
  begin
    //Memo1.Lines.Add(' Records ' + CDS.RecordCount.ToString);

    GStatus.dwLength := SizeOf(GStatus);
    GlobalMemoryStatusEx(GStatus);

    GetMemoryManagerState(MMState);
    var FastMM: Int64 := 0;
    for var i := 0 to High(MMState.SmallBlockTypeStates) do
      Inc(FastMM, MMState.SmallBlockTypeStates[i].UseableBlockSize * MMState.SmallBlockTypeStates[i].AllocatedBlockCount);
    Inc(FastMM, MMState.TotalAllocatedMediumBlockSize);
    Inc(FastMM, MMState.TotalAllocatedLargeBlockSize);

    Memo1.Lines.Add(Format(' Memory %d%% %.2nm %s%.2nm / %.2nm', [
      GStatus.dwMemoryLoad, Int64(GStatus.ullTotalVirtual - GStatus.ullAvailVirtual) / 1048576,
      IfThen(Mem < GStatus.ullAvailVirtual, '', '+'), Int64(Mem - GStatus.ullAvailVirtual) / 1048576,
      FastMM / 1048576
    ]));
    Mem := GStatus.ullAvailVirtual;
  end;
begin
  Mem := 0;
  CDS := TClientDataSet.Create(Self);
  CDS.FieldDefs.Add('TEST1', ftString, 500);
  CDS.FieldDefs.Add('TEST2', ftString, 500);
  CDS.FieldDefs.Add('TEST3', ftString, 500);
  CDS.CreateDataSet;
  CDS.LogChanges := False;

  for var L := 1 to 199 do
    try
      Memo1.Lines.Add(L.ToString);
      //Memo1.Lines.Add('Add');
      for var i := 1 to 9999 do begin
        CDS.Append;
        CDS.FieldByName('TEST1').AsString := Random(MaxInt).ToString;
        CDS.FieldByName('TEST2').AsString := Random(MaxInt).ToString;
        CDS.FieldByName('TEST3').AsString := Random(MaxInt).ToString;
        CDS.Post;
      end;
      ShowState;

      //Memo1.Lines.Add('Delete');
      {$IF false}
      while CDS.RecordCount > 0 do
        CDS.Delete;
      {$ELSE}
      CDS.EmptyDataSet;
      {$IFEND}
      ShowState;
    except
      on E: Exception do begin
        Memo1.Lines.Add(L.ToString + ' : ' + E.Message);
        ShowState;
        Break;
      end;
    end;
end;

lxo 2. Jun 2022 08:36

AW: Clientdataset Speicherfreigabe
 
Zitat:

Zitat von TigerLilly (Beitrag 1506680)
ApplyUpdates + Handler für BeforeApplyUpdates sollte das Delta leeren.

CDS schließen und öffnen.

CDS zerstören + neu erzeugen.

Ein anderes MemoryDataSet nehmen.

Das Problem ignorieren - in der Praxis sollte das doch nicht stören, oder was machst du da?

Ich verwende das Dataset für ein aktives Log.
Die letzten 25 Logeinträge werden dort angezeigt.
Bevor der 26.Eintrag geschrieben wird, wird der älteste Eintrag gelöscht.

Dabei ist mir das aufgefallen, obwohl ich immer nur 25 Einträge habe läuft der Speicher immer weiter voll.

himitsu 2. Jun 2022 11:20

AW: Clientdataset Speicherfreigabe
 
Wenn du nur die Datensätze überschreibst, anstatt zu löschen und neu zu erstellen, dann gibt es kein Problem.
Aber man sollte dringend LogChanges abschalten, denn erstmal bremst das ja ganz extrem und es verbrät dennoch ordentlich Speicher.

Delphi-Quellcode:
{$OVERFLOWCHECKS OFF}

uses
  System.StrUtils, Data.DB, Datasnap.DBClient;

procedure TForm8.FormCreate(Sender: TObject);
var
  CDS: TClientDataSet;
  Mem: UInt64;
procedure ShowState;
  var
    GStatus: TMemoryStatusEx;
    MMState: TMemoryManagerState;
  begin
    GStatus.dwLength := SizeOf(GStatus);
    GlobalMemoryStatusEx(GStatus);

    GetMemoryManagerState(MMState);
    var FastMM: Int64 := 0;
    for var i := 0 to High(MMState.SmallBlockTypeStates) do
      Inc(FastMM, MMState.SmallBlockTypeStates[i].UseableBlockSize * MMState.SmallBlockTypeStates[i].AllocatedBlockCount);
    Inc(FastMM, MMState.TotalAllocatedMediumBlockSize);
    Inc(FastMM, MMState.TotalAllocatedLargeBlockSize);

    Memo1.Lines.Add(Format(' Memory %d%% %.2nm %s%.2nm / %.2nm / %.1nk records / %.1nk changes', [
      GStatus.dwMemoryLoad, Int64(GStatus.ullTotalVirtual - GStatus.ullAvailVirtual) / 1048576,
      IfThen(Mem < GStatus.ullAvailVirtual, '', '+'), Int64(Mem - GStatus.ullAvailVirtual) / 1048576,
      FastMM / 1048576, CDS.RecordCount / 1000, CDS.ChangeCount / 1000
    ]));
    Mem := GStatus.ullAvailVirtual;
  end;
begin
  Mem := 0;
  CDS := TClientDataSet.Create(Self);
  CDS.FieldDefs.Add('TEST1', ftString, 500);
  CDS.FieldDefs.Add('TEST2', ftString, 500);
  CDS.FieldDefs.Add('TEST3', ftString, 500);
  CDS.CreateDataSet;
  CDS.LogChanges := False;

  for var i := 1 to 25 do begin
    CDS.Append;
    CDS.FieldByName('TEST1').AsString := Random(MaxInt).ToString;
    CDS.FieldByName('TEST2').AsString := Random(MaxInt).ToString;
    CDS.FieldByName('TEST3').AsString := Random(MaxInt).ToString;
    CDS.Post;
  end;
  ShowState;

  for var i := 1 to 100000 do
    try
      CDS.RecNo := i mod {25} CDS.RecordCount + 1;
      CDS.Edit;
      CDS.FieldByName('TEST1').AsString := Random(MaxInt).ToString;
      CDS.FieldByName('TEST2').AsString := Random(MaxInt).ToString;
      CDS.FieldByName('TEST3').AsString := Random(MaxInt).ToString;
      CDS.Post;
      if i mod 5000 = 0 then
        ShowState;
    except
      on E: Exception do begin
        Memo1.Lines.Add(i.ToString + ' : ' + E.Message);
        ShowState;
        Break;
      end;
    end;
  ShowState;
end;

TigerLilly 2. Jun 2022 11:24

AW: Clientdataset Speicherfreigabe
 
Vielleicht ist ein CDS auch nicht optimal für die Aufgabenstellung. Vielleicht wäre eine simple Liste passender? Oder wenn du es visualisiert haben willst, nimm eine TListBox + füttere dort jeweils 5 Items.

lxo 2. Jun 2022 16:03

AW: Clientdataset Speicherfreigabe
 
Zitat:

Zitat von TigerLilly (Beitrag 1506691)
Vielleicht ist ein CDS auch nicht optimal für die Aufgabenstellung. Vielleicht wäre eine simple Liste passender? Oder wenn du es visualisiert haben willst, nimm eine TListBox + füttere dort jeweils 5 Items.

Das kann gut sein, ich wollte nur gerne auch den Hintergrund wissen, wieso sich das TClientDataSet so verhält.
Hätte ich nicht erwartet, da auch andere DataSets von FireDAC oder DevExpress z.B. sich nicht so verhalten.

TigerLilly 6. Jun 2022 15:45

AW: Clientdataset Speicherfreigabe
 
Naja, DevEx und Firedac sind reine InMemory-Datasets + konsolidieren die Änderunggen eben nicht in einem Delta für n-Tier.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:09 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