AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Mein Programm ist Arbeitsspeicher hungrig..
Thema durchsuchen
Ansicht
Themen-Optionen

Mein Programm ist Arbeitsspeicher hungrig..

Ein Thema von Cubysoft · begonnen am 18. Mai 2015 · letzter Beitrag vom 20. Mai 2015
Antwort Antwort
Seite 1 von 3  1 23      
Cubysoft

Registriert seit: 5. Sep 2014
Ort: Ludwigshafen
76 Beiträge
 
Delphi XE8 Professional
 
#1

Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 21:54
Hey,

ich habe eine TList mit ca. 41.000 Einträgen. Jeder dieser Einträge besteht aus 12 Booleans und einem String (maximal 5 Zeichen). Und genau hier entsteht mein Problem. Ich speichere die Daten total hässlich im Textformal ab (bsp: Toll;1;0;1;0;1;0;..). Die Datei ist gerade mal ~1MB groß. Wird das ganze aber in den Arbeitsspeicher geladen, nimmt es riesige Ausmaße an und ist 100MB groß. Woran liegt das denn bitte?
Tobias
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.861 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 22:04
Wie sieht die Datenstruktur eines Eintrages aus?
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#3

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 22:09
Woran liegt das denn bitte?
42.

Ich darf auch mal .

Ne, mal im Ernst: Ohne Code und die Kenntnis der Datenstruktur wird da keiner etwas dazu sagen können.

MfG Dalai
  Mit Zitat antworten Zitat
Cubysoft

Registriert seit: 5. Sep 2014
Ort: Ludwigshafen
76 Beiträge
 
Delphi XE8 Professional
 
#4

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 22:48
Achso klar, dachte das reicht:

Delphi-Quellcode:
IDListEx: TList<TTeUpdateDBIDState>;

und

TTeUpdateDBIDState = record
    id: String;
    AccountBindOnUse: Boolean;
    AccountBound: Boolean;
    HideSuffix: Boolean;
    MonsterOnly: Boolean;
    NoMysticForge: Boolean;
    NoSalvage: Boolean;
    NoSell: Boolean;
    NotUpgradeable: Boolean;
    NoUnderwater: Boolean;
    SoulbindOnAcquire: Boolean;
    SoulBindOnUse: Boolean;
    Unique: Boolean;
  end;

wobei der String zwischen 1 und 5 Zeichen schwankt, aber nie größer ist. Die Liste wird dann während der Laufzeit gefüllt und hat am and ~41.000 Einträge was 100MB Arbeitsspeicher bedeutet
Tobias
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#5

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 23:08
Und wie genau liest du die Daten ein?

MfG Dalai
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 23:17
Kann ich nicht nachvollziehen
Delphi-Quellcode:
program dp_185142;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Generics.Collections,
  System.SysUtils;

type
  TTeUpdateDBIDState = record
    id: string;
    AccountBindOnUse: Boolean;
    AccountBound: Boolean;
    HideSuffix: Boolean;
    MonsterOnly: Boolean;
    NoMysticForge: Boolean;
    NoSalvage: Boolean;
    NoSell: Boolean;
    NotUpgradeable: Boolean;
    NoUnderwater: Boolean;
    SoulbindOnAcquire: Boolean;
    SoulBindOnUse: Boolean;
    Unique: Boolean;
  end;

procedure Test;
var
  IDListEx: TList<TTeUpdateDBIDState>;
  LItem: TTeUpdateDBIDState;
begin
  // TaskManager -> 588KB
  IDListEx := TList<TTeUpdateDBIDState>.Create;
  try
    while IDListEx.Count < 41000 do
    begin
      LItem.id := ( IDListEx.Count + 1 ).ToString;
      IDListEx.Add( LItem );
    end;
  finally
    // TaskManager -> 2892KB
    IDListEx.Free;
  end;
end;

begin
  try
    Test;
  except
    on E: Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;
  // TaskManager -> 1864KB
  ReadLn;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Cubysoft

Registriert seit: 5. Sep 2014
Ort: Ludwigshafen
76 Beiträge
 
Delphi XE8 Professional
 
#7

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 23:43
Okay bin ratlos. Da habt ihr meinen Code..

Delphi-Quellcode:
unit TeUpdateDB;

interface

uses
  System.Generics.Collections,IdHTTP, System.Threading,
  IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL,
  System.Classes;

type
  TTeUpdateDBStatus = record
    id: Integer;
    current,max: Integer;
  end;
  TTeUpdateDBIDState = record
    id: String;
    AccountBindOnUse: Boolean;
    AccountBound: Boolean;
    HideSuffix: Boolean;
    MonsterOnly: Boolean;
    NoMysticForge: Boolean;
    NoSalvage: Boolean;
    NoSell: Boolean;
    NotUpgradeable: Boolean;
    NoUnderwater: Boolean;
    SoulbindOnAcquire: Boolean;
    SoulBindOnUse: Boolean;
    Unique: Boolean;
  end;

type
  TTeUpdateDB = class(TObject)
  private
    IDList: TStringList;
    IDListEx: TList<TTeUpdateDBIDState>;
    IDListTask: ITask;
    procedure AddToIDListEx(sl: TStringList;fstart,fend:Integer);
    procedure BuiltIDList;
    procedure BuiltIDListEx(fstart, fend: Integer);
    function CountEntries(s: String): Integer;
    procedure SplitEntries(sl: TStringList; s: String);

    function BToStr(b:Boolean): String;
  public
    state: TTeUpdateDBStatus;
    constructor Create;
    procedure GetIDInformation;
    procedure SaveIDListEx(p: String);
  end;

implementation

uses
  System.SysUtils, Vcl.Dialogs;

const
  maxidrequ = 200;

constructor TTeUpdateDB.Create;
begin
  IDList := TStringList.Create;
  IDListEx := TList<TTeUpdateDBIDState>.Create;
  state.id := -2;
end;


procedure TTeUpdateDB.GetIDInformation;
begin
  IDListTask := TTask.Create(procedure()
  var
    max,fstart,fend: Integer;
  begin
    BuiltIDList;
    //debugging
    state.id := 0;
    max := IDList.Count -1;
    state.max := max;
    fstart := 0; fend := -1;

    IDListEx.Clear;

    while fend <> max do
    begin
      fstart := fend + 1;
      fend := fstart + (maxidrequ-1);
      state.current := fstart;
      if fend > max then fend := max;
      if fstart > fend then break;
      BuiltIDListEx(fstart,fend);
    end;

    //debugging
    SaveIDListEx('test.dat');
  end);
  IDListTask.Start;
end;


procedure TTeUpdateDB.SaveIDListEx(p: string);
var
  sl:TStringList;
  i: Integer;
begin
  sl := TStringList.Create;
  for i := 0 to IDListEx.Count-1 do
  begin
    sl.Add(IDListEx[i].id + ';' + BToStr(IDListEx[i].AccountBindOnUse) + ';' + BToStr(IDListEx[i].AccountBound) + ';' + BToStr(IDListEx[i].HideSuffix) + ';' + BToStr(IDListEx[i].MonsterOnly) + ';' + BToStr(IDListEx[i].NoMysticForge) + ';' + BToStr(IDListEx[i].NoSalvage) + ';' + BToStr(IDListEx[i].NoSell) + ';' + BToStr(IDListEx[i].NotUpgradeable) + ';' + BToStr(IDListEx[i].NoUnderwater) + ';' + BToStr(IDListEx[i].SoulbindOnAcquire) + ';' + BToStr(IDListEx[i].SoulBindOnUse) + ';' + BToStr(IDListEx[i].Unique));
  end;
  sl.SaveToFile(p,TEncoding.UTF8);
end;

//###########################################################################################################
procedure TTeUpdateDB.BuiltIDList;
var
  http: TIdHttp;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  buffer: String;
begin
  IDList.Clear;
  http := TIdHTTP.Create;
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  http.IOHandler := ssl;

  buffer := http.Get('https://url.de/items');

  buffer := StringReplace(buffer,'[','',[]);
  buffer := StringReplace(buffer,']','',[]);

  IDList.StrictDelimiter := True;
  IDList.Delimiter := ',';
  IDList.DelimitedText := buffer;
end;

procedure TTeUpdateDB.BuiltIDListEx(fstart,fend: Integer);
var
  http: TIdHttp;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  buffer: String;
  ids: String;
  i: Integer;
  sl: TStringList;
begin
  http := TIdHTTP.Create;
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  http.IOHandler := ssl;
  sl := TStringList.Create;

  try
    ids := '';
    for i := fstart to fend do
    begin
      if i <> fend then
        ids := ids + IDList[i] + ','
      else
        ids := ids + IDList[i];
    end;

    buffer := http.Get('https://url.de/items?ids=' + ids);
    SplitEntries(sl,buffer);

    //debugging
    if sl.Count <> CountEntries(buffer) then state.id := -1;

    AddToIDListEx(sl,fstart,fend);
  finally
    sl.Free;
  end;

end;

procedure TTeUpdateDB.AddToIDListEx(sl: TStringList; fstart: Integer; fend: Integer);
var
  i: Integer;
  d: TTeUpdateDBIDState;
  pf: Integer;
begin
  for i := 0 to sl.Count -1 do
  begin
    d.id := IDList[fstart+i];
    pf := Pos('"flags":',sl[i]);
    if pf = 0 then
    begin
      d.AccountBindOnUse := false;
      d.AccountBound := false;
      d.HideSuffix := false;
      d.MonsterOnly := false;
      d.NoMysticForge := false;
      d.NoSalvage := false;
      d.NoSell := false;
      d.NotUpgradeable := false;
      d.NoUnderwater := false;
      d.SoulbindOnAcquire := false;
      d.SoulBindOnUse := false;
      d.Unique := false;
    end else
    begin
      d.AccountBindOnUse := (Pos('"AccountBindOnUse"',sl[i],pf) <> 0);
      d.AccountBound := (Pos('"AccountBound"',sl[i],pf) <> 0);
      d.HideSuffix := (Pos('"HideSuffix"',sl[i],pf) <> 0);
      d.MonsterOnly := (Pos('"MonsterOnly"',sl[i],pf) <> 0);
      d.NoMysticForge := (Pos('"NoMysticForge"',sl[i],pf) <> 0);
      d.NoSalvage := (Pos('"NoSalvage"',sl[i],pf) <> 0);
      d.NoSell := (Pos('"NoSell"',sl[i],pf) <> 0);
      d.NotUpgradeable := (Pos('"NotUpgradeable"',sl[i],pf) <> 0);
      d.NoUnderwater := (Pos('"NoUnderwater"',sl[i],pf) <> 0);
      d.SoulbindOnAcquire := (Pos('"SoulbindOnAcquire"',sl[i],pf) <> 0);
      d.SoulBindOnUse := (Pos('"SoulBindOnUse"',sl[i],pf) <> 0);
      d.Unique := (Pos('"Unique"',sl[i],pf) <> 0);
    end;
    IDListEx.Add(d);
  end;
end;

function TTeUpdateDB.CountEntries(s: String): Integer;
var
  p: Integer;
begin
  p := 1;
  result := 0;
  while p <> 0 do
  begin
    p := Pos('{"name":',s,p+1);
    if p <> 0 then Inc(result);
  end;
end;

procedure TTeUpdateDB.SplitEntries(sl: TStringList; s: String);
var
  p, pp: Integer;
  b: Boolean;
begin
  sl.Clear;
  b := true;
  p := 0;
  while b do
  begin
    p := Pos('{"name":',s,p+1); //1.Item
    pp := Pos('{"name":',s,p+1); //2.Item
    if pp = 0 then
    begin
      b := false;
      pp := Length(s);
    end else
    begin
      pp := pp - 1;
    end;
    sl.Add(Copy(s,p,pp-p));
  end;
end;

function TTeUpdateDB.BToStr(b: Boolean): String;
begin
  if b then result := '1else result := '0';
end;

end.
Aufgerufen wird die GetIDInformation-Funktion..
Tobias
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 18. Mai 2015, 23:57
41.000 * 16 Record-Bytes = 656.000 Byte (TList legt das in einem Block in den RAM ... bei 64 KB-Speicherblöcken macht das 10,0098 Blöcke = aufgerundet 11*64 = 720.896 Bytes)
+
41.000 * (4 Längen-Bytes + 2 CharSize-Bytes + 2 CodepageBytes + 2*2 abschließende #0-Bytes + 5*2 Unicode-Bytes) = 22 ... FastMM wird das vermutlich im 32er-Block ablegen = 1.312.000 Bytes

effektiv also 2 MB (in Delphi ab Version 2009)
und dazu kommt dann noch die VCL, usw.


aber jetzt kommt es noch darauf an, was du eigentlich soonst noch machst, vorallem mit den Strings,
wie du die Liste befüllst (mit oder einer passenden Capacity)
und wie die deine Speicherverwaltung aussieht,
was du für eine Delphiversion benutzt uvm.

Wenn das wirklich so viel wird dann liegt das vermutlich an dir und eventuell einer wunderschönen Speicherfragmentierung.



Was sagt denn z.B. GetHeapStatus, GetMemoryManagerState, wieviel es wirklich ist?
Und wie sieht es mit Speicherlecks aus? (ReportMemoryLeaksOnShutdown)

[edit] Deine code hab ich mir jetzt nicht angesehn (ist auch schon spät)
$2B or not $2B

Geändert von himitsu (19. Mai 2015 um 00:04 Uhr)
  Mit Zitat antworten Zitat
hathor
(Gast)

n/a Beiträge
 
#9

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 19. Mai 2015, 00:21
Das lässt sich viel besser speichern:

EinString : array [0..4] of ANSIChar; // 5 Bytes * 41000 = 205 kB
BooleanWerte :
uses System.Classes.TBits.Bits
var
Bits: TBits;
I: Byte;
begin
{ Create a a bit set. }
Bits := TBits.Create;
{ Set the size of the bit set. }
Bits.Size := 12; // 12 BooleanWerte 61,5 kB
------------------------------------------SUMME : 266,5 kB
http://docwiki.embarcadero.com/Libra...#Code_Examples

Geändert von hathor (19. Mai 2015 um 09:32 Uhr)
  Mit Zitat antworten Zitat
Cubysoft

Registriert seit: 5. Sep 2014
Ort: Ludwigshafen
76 Beiträge
 
Delphi XE8 Professional
 
#10

AW: Mein Programm ist Arbeitsspeicher hungrig..

  Alt 19. Mai 2015, 00:38
schaut euch mal bitte meine Code an. Das ist alles. Was ist daran falsch, bzw wieso wird so viel Speicher verbraucht? Die Strings die heruntergeladen werden sind schon relativ groß ~1-2MB allerdings sollten die ja im Grunde keine Rolle spielen, da sie nur lokal sind und dann nicht im speicher bleiben.. Also woran kann das liegen?
Tobias
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 13:49 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