Delphi-PRAXiS
Seite 5 von 7   « Erste     345 67      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Memory leak durch funktion readln (https://www.delphipraxis.net/184250-memory-leak-durch-funktion-readln.html)

p80286 12. Mär 2015 23:22

AW: Memory leak durch funktion readln
 
Tja wer mißt misst Mist:
Datei schreiben:
ticks für file1: 998
ticks für file2: 9079
ticks für file1: 5304
ticks für file2: 9313
ticks für file1: 8346
ticks für file2: 10093


Datei lesen:
readticks für file1: 515
readticks für file2: 32
readticks für file1: 515
readticks für file2: 15
readticks für file1: 499
readticks für file2: 31

und hier der Source: (der Mißbrauch von written sei mir vergeben):
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
const
  file1='c:\temp\f1.bin';
  file2='c:\temp\f2.bin';
  buffersize=8192;
  maxblocks=$FFFF;
var
  i : integer;
  fn1,
  fn2 : tfilestream;
  dat1,
  dat2 : file;
  buffer : array [0..buffersize-1] of byte;
  sz1,sz2 : integer;
  ez1,ez2 : integer;
  written : integer;
begin
  assignfile(dat1,file1);
  rewrite(dat1,1);
  fillchar(buffer,buffersize,'A');
  sz1:=gettickcount;
  for i:=0 to maxblocks do blockwrite(dat1,buffer,buffersize);
  ez1:=gettickcount;
  closefile(dat1);

  memo1.Lines.Add(format('ticks für file1: %d',[ez1-sz1]));

  fn1:=tfilestream.Create(file2,fmcreate or fmshareexclusive );
  sz2:=gettickcount;
  for i:=0 to maxblocks do written:=fn1.Write(buffer,buffersize);
  ez2:=gettickcount;
  fn1.Free;
  memo1.Lines.Add(format('ticks für file2: %d',[ez2-sz2]));
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  file1='c:\temp\f1.bin';
  file2='c:\temp\f2.bin';
  buffersize=8192;
  maxblocks=$FFFF;
var
  i : integer;
  fn1,
  fn2 : tfilestream;
  dat1,
  dat2 : file;
  buffer : array [0..buffersize-1] of byte;
  sz1,sz2 : integer;
  ez1,ez2 : integer;
  written : integer;
begin
  assignfile(dat1,file1);
  reset(dat1,1);
  fillchar(buffer,buffersize,'A');
  sz1:=gettickcount;
  for i:=0 to maxblocks do blockread(dat1,buffer,buffersize);
  ez1:=gettickcount;
  closefile(dat1);

  memo1.Lines.Add(format('readticks für file1: %d',[ez1-sz1]));

  fn1:=tfilestream.Create(file2,fmopenread or fmshareexclusive );
  sz2:=gettickcount;
  for i:=0 to maxblocks do written:=fn1.Write(buffer,buffersize);
  ez2:=gettickcount;
  fn1.Free;
  memo1.Lines.Add(format('readticks für file2: %d',[ez2-sz2]));
end;
Wenn ich beim reset/rewrite statt 1 buffersize nutze, gibt es keine signifikante Abweichung.

Ach ja W7-64 und die Festplatte in meinem Laptop.

Die paar hunderstel Unterschied, die Du gemessen hast, würde ich übrigens als Meßfehler abhaken.

Gruß
K-H

Mavarik 12. Mär 2015 23:49

AW: Memory leak durch funktion readln
 
OK Neue Testbedingung.

Nativ Windows 8 keine VM. Mächtig große Datei, daher weniger Try's weil es mir sonst zu lange gedauert hätte!

Lesen von 29996224 KB - gelesen in Häppchen zu 1048576 KB

Versuch 1 : Blockread(45643 ms) StreamRead(45811 ms) 1:0
Versuch 2 : Blockread(45977 ms) StreamRead(45839 ms) 1:1
Versuch 3 : Blockread(45820 ms) StreamRead(45768 ms) 1:2
Versuch 4 : Blockread(45287 ms) StreamRead(45424 ms) 2:2
Versuch 5 : Blockread(45168 ms) StreamRead(45305 ms) 3:2

Best Blockread 648,54 MB/s Best StreamRead 646,58 MB/s

Blockread gewinnt...

Stopwatch ist da ziemlich genau... Aber bei 45 Sekunden ein Unterschied von 137 ms...
Na gut...

Meine Rede Blockread & StreamRead sind fast die gleichen Routinen... Bei 4,43 GHz fällt das aber selbst bei so vielen Operationen nicht auf...

Mavarik

Mavarik 12. Mär 2015 23:57

AW: Memory leak durch funktion readln
 
hmm wenn ich Deine Zahlen richtig sehen...

Blockwrite schneller als Streamwrite
StreamRead schneller als Blockread...

Komisch...

Aber Du hast natürlich sehr keine Blockgrößen genommen...

Delphi-Quellcode:
var
  Puffer : array [0..1024*1024*1024-1] of byte;

implementation

Uses System.Diagnostics;

procedure TForm42.Button1Click(Sender: TObject);
var
  F       : File;
  FS      : TFileStream;
  SW      : TStopWatch;
  BR,ST   : array[0..9] of Int64;
  I       : Integer;
  Gelesen : Integer;
  Filename : String;

begin
  Filename := 'Big.iso';

  Memo1.Lines.Text := 'Lesen von '+(GetFilesize('Big.iso') / 1024).ToString+' KB - gelesen in Häppchen zu '+(Sizeof(Puffer) / 1024).ToString+' KB';


  for i:=0 to 5 do
    begin
      AssignFile(F,Filename);
      Reset(F,1);

      SW := TStopWatch.StartNew;
      SW.Start;

      repeat
        Blockread(F,Puffer[0],Sizeof(Puffer),gelesen);
      until gelesen = 0;

      SW.Stop;

      Closefile(F);

      BR[I] := SW.ElapsedMilliseconds;

      FS := TFileStream.Create(Filename,fmopenRead);
      SW := TStopWatch.StartNew;
      SW.Start;
      repeat
        gelesen := FS.Read(Puffer[0],Sizeof(Puffer));
      until gelesen = 0;
      SW.Stop;
      FS.Free;

      ST[I] := SW.ElapsedMilliseconds;
      Memo1.Lines.Add('Versuch '+i.ToString+' : Blockread('+BR[i].ToString+' ms) StreamRead('+ST[i].ToString+' ms)');

      Application.ProcessMessages;
    end;
end;

BUG 13. Mär 2015 01:22

AW: Memory leak durch funktion readln
 
Der Vorteil von Filestreams liegt ja nicht direkt an der Geschwindigkeit, sondern an der Abstraktion.

Klar ist es schnell mit großen Buffern* zu arbeiten. Aber die meisten Anwendungen lesen logisch häufig kleinere Strukturen. Nun könnte man in der Anwendungslogik irgendeine Bufferverwaltung fest verdrahten; oder man ließt einfach die Größe, die was man gerade braucht, aus einem Stream.

Um die Performanz zu verbessern, kann man jetzt eine beliebige Bufferverwaltung, Caches, usw. in einen Stream verpacken und benutzen, ohne den Algorithmus anfassen zu müssen. Und das alles zum Preis von ein paar virtuellen Methodenaufrufen :mrgreen:

* Zu große Puffer sind auch nicht das Wahre: Das Betriebssystem schreibt die womöglich flugs wieder in die Auslagerungsdatei, so dass die beim nächsten Zugriff noch mal von der Platte gekratzt werden müssen.

himitsu 13. Mär 2015 01:45

AW: Memory leak durch funktion readln
 
Bei den "alten" Datei-Prozeduren hat standardmäßig erstmal nur TEXT einen kleinen 127-Byte Puffer, was sogesehn auch nicht grade optimal ist, da Windows und Hardware Speicher in Größen mit Vielfachen von 512 verwaltet (kleinster Sektor = 512 und das ist heute bei durchschnittlich über 8 KB) und auch der RAM wird in 64-KB-Schritten verwaltet.
Und dann geht/ging man davon auß, daß eine Zeile meistens nicht größer als 127 Byte (ANSI-Zeichen) ist.

Zitat:

Zitat von BUG (Beitrag 1293311)
oder man ließt einfach die Größe, die was man gerade braucht,

Gerade beim Textauslesen geht es ohne Puffer nicht schön, da man eben nicht weiß wieviel mal lesen muß/will.
In binären Formaten gibt es da fast immer feste Größen, bzw. man hat vor den Daten irgendwo eine Größenangabe in Byte/Wort/Integer/... die ja selber wieder eine feste Größe besitzen.

danieldelphi 13. Mär 2015 09:29

AW: Memory leak durch funktion readln
 
Zitat:

Zitat von Jasocul (Beitrag 1293189)
Naja, wenn ich es richtig sehe, bekommt "autodatei" kein Close.
Das mag Windows überhaupt nicht, weil dadurch File-Handles nicht wieder freigegeben werden. Das kann in der Folge dann auch zu Memory-Leaks führen.

Mal abgesehen davon, dass in der inneren While-Schleife ein Exit steht. Wodurch keine einzige Datei-Variable mehr freigegeben wird.

Oder habe ich das Close für autodatei übersehen?

Also das exit und die autodatei sind nicht das problem, da in dem code den ich zuanfang gepostet habe beides nicht vorhanden ist aber das problem trotzdem auftritt.

p80286 13. Mär 2015 09:59

AW: Memory leak durch funktion readln
 
Zitat:

Zitat von Mavarik (Beitrag 1293308)
hmm wenn ich Deine Zahlen richtig sehen...

Blockwrite schneller als Streamwrite
StreamRead schneller als Blockread...

Komisch...

Jo, ist mir beim Frühstück auch aufgefallen, das Sttream.Read war ein Stream.Write :oops:
Jetzt entspricht das Ergebnis Deinen Zahlen, mit leichen Vorteilen für's Streamread. Sei's drum, halten wir fest, beim lesen tun die beiden sich nich(s/ viel) und beim Schreiben hat Blockwrite die Nase vorn.

Gruß
K-H

Mavarik 13. Mär 2015 10:08

AW: Memory leak durch funktion readln
 
Zitat:

Zitat von BUG (Beitrag 1293311)
Der Vorteil von Filestreams liegt ja nicht direkt an der Geschwindigkeit, sondern an der Abstraktion.

Völlig korrekt... Vorausgesetzt man arbeitet mit Streams... Wenn der Rest der Application Blockread/write nimmt hilft das auch nicht...

Zugegeben die Verwendung von TStream in Grundroutinen macht Sinn, wem man diese dann mit Memory- oder Filestream aufrufen kann...

Bei Dateien < Meine_Max_Puffergröße lad ich egal was einfach ins RAM und go... Klar kann ich auch eine Textdatei Zeilenweise einlesen...
Aber eine 1MB Textdatei in einem rutsch in den Puffer und dann mit einem
Delphi-Quellcode:
Zeiger : ^Char
durchlaufen ist echt schneller, wenn ich "nur" etwas Suche!

Mavarik

danieldelphi 13. Mär 2015 10:13

AW: Memory leak durch funktion readln
 
Zitat:

Zitat von Mavarik (Beitrag 1293340)
Zitat:

Zitat von BUG (Beitrag 1293311)
Der Vorteil von Filestreams liegt ja nicht direkt an der Geschwindigkeit, sondern an der Abstraktion.

Völlig korrekt... Vorausgesetzt man arbeitet mit Streams... Wenn der Rest der Application Blockread/write nimmt hilft das auch nicht...

Zugegeben die Verwendung von TStream in Grundroutinen macht Sinn, wem man diese dann mit Memory- oder Filestream aufrufen kann...

Bei Dateien < Meine_Max_Puffergröße lad ich egal was einfach ins RAM und go... Klar kann ich auch eine Textdatei Zeilenweise einlesen...
Aber eine 1MB Textdatei in einem rutsch in den Puffer und dann mit einem
Delphi-Quellcode:
Zeiger : ^Char
durchlaufen ist echt schneller, wenn ich "nur" etwas Suche!

Mavarik

Ich misch mich grade nochmal in eure Diskussion ein, also ich ahbe mittlerweile rausgefunden, dass der Arbeitsspeicher scheinbar nicht von meinem Delphi tool blockiert wird, sondern von etwas anderem, also kann es ja nur die Datei verwaltung oder windows sein ioder?
dagegen kann man nix machenn oder?

danieldelphi 13. Mär 2015 10:18

AW: Memory leak durch funktion readln
 
Zitat:

Zitat von Mavarik (Beitrag 1293156)
Hast Du das mal mit {$R+,O+} compiliert?

hat nichts gebracht


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:30 Uhr.
Seite 5 von 7   « Erste     345 67      

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