AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Clientdataset Speicherfreigabe

Ein Thema von lxo · begonnen am 31. Mai 2022 · letzter Beitrag vom 6. Jun 2022
Antwort Antwort
Seite 1 von 2  1 2      
lxo

Registriert seit: 30. Nov 2017
288 Beiträge
 
Delphi 12 Athens
 
#1

Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 15:38
Hallo zusammen,

wieso wird beim TClientdataset der Speicher nicht freigegeben wenn man Datensätze löscht?
Muss ich da noch irgendetwas auslösen? Beim TFDMemTable wird der Speicher direkt nach dem löschen wieder freigegeben.

Delphi-Quellcode:
unit Unit121;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Datasnap.DBClient, Vcl.StdCtrls,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
  FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
  FireDAC.Comp.DataSet, FireDAC.Comp.Client;

type
  TForm121 = class(TForm)
    gb_clientdataset: TGroupBox;
    b_clientdataset_add: TButton;
    b_clientdataset_delete: TButton;
    l_clientdataset: TLabel;
    gb_fdmemtable: TGroupBox;
    l_fdmemtable: TLabel;
    b_fdmemtable_add: TButton;
    b_fdmemtable_delete: TButton;
    procedure b_clientdataset_addClick(Sender: TObject);
    procedure b_clientdataset_deleteClick(Sender: TObject);
    procedure b_fdmemtable_addClick(Sender: TObject);
    procedure b_fdmemtable_deleteClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    lClientDataSet: TClientDataSet;
    lFDMemTable: TFDMemTable;
    procedure Add( xDataset: TDataSet;
                   xLabel: TLabel);
    procedure Delete( xDataset: TDataSet;
                      xLabel: TLabel);
  end;

var
  Form121: TForm121;

implementation

{$R *.dfm}

procedure TForm121.Add(xDataset: TDataSet; xLabel: TLabel);
begin
  for var i := 1 to 9999 do
  begin
    xDataset.Append;
    xDataset.FieldByName('TEST1').AsString := Random( MaxInt).ToString;
    xDataset.FieldByName('TEST2').AsString := Random( MaxInt).ToString;
    xDataset.FieldByName('TEST3').AsString := Random( MaxInt).ToString;
    xDataset.Post;
  end;
  xLabel.Caption := Format( 'Recordcount: %d', [ xDataset.RecordCount]);
end;

procedure TForm121.b_clientdataset_addClick(Sender: TObject);
begin
  Add( lClientDataSet,
       l_clientdataset);
end;

procedure TForm121.b_clientdataset_deleteClick(Sender: TObject);
begin
  Delete( lClientDataSet,
          l_clientdataset);
end;

procedure TForm121.b_fdmemtable_addClick(Sender: TObject);
begin
  Add( lFDMemTable,
       l_fdmemtable);
end;

procedure TForm121.b_fdmemtable_deleteClick(Sender: TObject);
begin
  Delete( lFDMemTable,
          l_fdmemtable);
end;

procedure TForm121.Delete(xDataset: TDataSet; xLabel: TLabel);
begin
  while ( xDataset.RecordCount > 0) do
  begin
    xDataset.Delete;
  end;
  xLabel.Caption := Format( 'Recordcount: %d', [ xDataset.RecordCount]);
end;

procedure TForm121.FormCreate(Sender: TObject);
begin
  Randomize;
  lClientDataSet := TClientDataSet.Create( Self);
  lClientDataSet.FieldDefs.Add( 'TEST1', ftString, 500);
  lClientDataSet.FieldDefs.Add( 'TEST2', ftString, 500);
  lClientDataSet.FieldDefs.Add( 'TEST3', ftString, 500);
  lClientDataSet.CreateDataSet;

  lFDMemTable := TFDMemTable.Create( Self);
  lFDMemTable.FieldDefs.Add( 'TEST1', ftString, 500);
  lFDMemTable.FieldDefs.Add( 'TEST2', ftString, 500);
  lFDMemTable.FieldDefs.Add( 'TEST3', ftString, 500);
  lFDMemTable.CreateDataSet;
end;

end.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#2

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 15:50
Hast du es mal mit MergeChangeLog probiert?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
lxo

Registriert seit: 30. Nov 2017
288 Beiträge
 
Delphi 12 Athens
 
#3

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 16:02
Hast du es mal mit MergeChangeLog probiert?
Wenn ich nach dem Insert und nach dem Delete MergeChangeLog ausführe habe ich den Unterschied, dass beim erneuten Insert von 9999 Datensätzen er vermutlich den selben Speicher verwendet. Trotzdem wird der Speicher nicht freigegeben.

Wenn ich nur an einer stelle Insert oder Delete MergeChangeLog ausführe wächst die Auslastung bei jedem neuen Insert.

LogChanges hilft auch nicht.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#4

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 16:10
Welcher Speicher wächst?

Ich tippe mal auf eine Speicherfragmentierung im FastMM.
Was sagt denn GetMemoryManagerState?



Hat ein billiges ClientDataSet überhaupt ein ChangeLog?
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (31. Mai 2022 um 16:13 Uhr)
  Mit Zitat antworten Zitat
lxo

Registriert seit: 30. Nov 2017
288 Beiträge
 
Delphi 12 Athens
 
#5

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 16:55
Welcher Speicher wächst?

Ich tippe mal auf eine Speicherfragmentierung im FastMM.
Was sagt denn GetMemoryManagerState?



Hat ein billiges ClientDataSet überhaupt ein ChangeLog?
Die Arbeitsspeicherauslastung (Arbeitsspeicher aktiver privater Arbeitssatz), wird beim entfernen von Datensätzen nicht kleiner.



Clientdataset
  1. Programm Start - 2648K
  2. Add - 18900K
  3. Delete - 18800K
  4. Add - 33476K
  5. Delete - 33476K
  6. Add - 48792K

FDMemTable
  1. Programm Start - 2596K
  2. Add - 19648K
  3. Delete - 6852K
  4. Add - 19712K
  5. Delete - 6912K
  6. Add - 19712K

Was sagt denn GetMemoryManagerState?
- Da steht immer das selbe hättest du da ein Beispiel wie ich das richtig anwende bzw. was möchtest du da genau sehen?



Beim dxMemTable von DevExpress wird der Speicher auch freigegeben.
Wenn ich bei einer TList oder TObjectList Einträge entferne werden die auch direkt freigegeben.
Ich hab das Problem nur bei TClientDataSets
  Mit Zitat antworten Zitat
lxo

Registriert seit: 30. Nov 2017
288 Beiträge
 
Delphi 12 Athens
 
#6

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 18:22
Hier nochmal das komplette Testprojekt.
Angehängte Dateien
Dateityp: zip Testproject.zip (1,8 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#7

AW: Clientdataset Speicherfreigabe

  Alt 31. Mai 2022, 18:23
Die scheinen den Speicher direkt bei Windows zu reservieren.

Hmmm, im FastMM steigt nichts an.
Aber im Code (Datasnap.DBClient) finde ich nur ein AllocMem, was eigentlich im Delphi-MemoryManager (FastMM) landen sollte.

Ich komm nach genügend Durchläufen (Add+Delete) sogar in einen OutOfMemory.


Delphi-Quellcode:
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;

  for var L := 1 to 99 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');
      while CDS.RecordCount > 0 do
        CDS.Delete;
      ShowState;
    except
      on E: Exception do begin
        Memo1.Lines.Add(L.ToString + ' : ' + E.Message);
        ShowState;
        Break;
      end;
    end;
end;
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#8

AW: Clientdataset Speicherfreigabe

  Alt 1. Jun 2022, 10:56
Vielleicht ist es nicht jedem bewusst, aber die DB-Engine des TClientDataset liegt in der Midas.dll bzw. ihrem eingelinkten binären Zwilling. Damit arbeitet es schon etwas anders als die reine Delphi-Implementierung von FireDAC.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
1.205 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Clientdataset Speicherfreigabe

  Alt 1. Jun 2022, 16:48
Die ClientDataSets sind ja eigentlich für n-tier Anwendungen gemacht, hängen also an einem Provider, der die das Änderungslog (DELTA) weiterreicht. Ein DELETE löscht also nicht wirklich, sondern hebt alles auf, was notwendig ist, um die Änderung weiterreichen zu können UND um das Löschen auch rückgängig machen zu können. Siehe "CancelUpdates".
Es überrascht mich also nicht, dass Speicher alloziert bleibt.

Jedes Feld gibt es im CDS 3x: newValue/Value/oldValue - da kommt im Code unten schon (unrealistischerweise) was zusammen: 99 x 9999 x 3 x 3 x 500

Mit dem Zerstören des CDS wird dann auch der Speicher freigegeben.
  Mit Zitat antworten Zitat
Frickler

Registriert seit: 6. Mär 2007
Ort: Osnabrück
591 Beiträge
 
Delphi XE6 Enterprise
 
#10

AW: Clientdataset Speicherfreigabe

  Alt 1. Jun 2022, 17:32
Einfach mal nach "CreateDataSet" die Property "LogChanges" auf false setzen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:36 Uhr.
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