Autor Beitrag
starsurfer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 334

Win 95, Win 98, Win XP, Win Vista, Linux
D5 Enterprise ,D2005, D6 Personal, Visual C++ Express 2005, C++ Builder 6 E, Dev-C++
BeitragVerfasst: So 28.05.06 12:08 
Ich schreibe zZ an einem Programm was alle Datein auf meinem Comp nach Änderungen überprüfen soll.
Dazu muss ich natürlich alle Dateien suchen,Auflisten,Größe speichern... usw...

Allerdings taucht ein extremes Problem auf.
Will ich alle Dateien auf meinem Comp suchen (ca 300000) sagt er das zu wenig RAM da ist.

Allein wenn ich nur C: durchsuche (40206 Datein/4,3GB) braucht er 400MB RAM !?

Dabei speicher ich meine gefundenen Datein wie folgt:
Datei Pfad und Datei Größe in einem Dynamischen Array...

hier die Procedure
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
type
  TDateien = record
   pfad:array of string;
   size:array of integer;
   end;

function SucheDateien(pfad,Maske:string;Unterordner:bool):TDateien;
var c:char;
procedure suchen(const Pfad:string);
var SR: TSearchRec;
begin
  if FindFirst(Pfad + Maske, faAnyFile - faDirectory, SR) = 0 then
  try
    repeat
      result.pfad[length(result.pfad)-1]:=pfad + SR.Name;
      result.size[length(result.size)-1]:=sr.Size;
      setlength(result.pfad,length(result.pfad)+1);
      setlength(result.size,length(result.size)+1);
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;

  if Unterordner then begin
    if FindFirst(pfad + '*.*', faAnyFile, SR) = 0 then
    try
      repeat
        if ((SR.attr and faDirectory) = faDirectory) and
           (SR.Name <> '.'and (SR.Name <> '..'then
          suchen(pfad + SR.Name + '\');
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
  end;

end;

begin
try
setlength(result.pfad,1);
setlength(result.size,1);
suchen(pfad);
except
 showmessage('Fehler beim Suchen');
end;
end;


Was braucht hier so immens viel RAM?
Wie kann ich das Abstellen?

_________________
GEIZ IST GEIL! - Ihr Sozialamt
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 28.05.06 12:29 
Oh Gott, sind da viele Todsünden mit einem Schlag enthalten ...

Die gröbsten:

1. Dein Record-Typ sollte andersrum lauten:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
type
    TDateien = array of record
        Pfad: String;
        Size: Integer;
    end;


2. Ständiges Realloziieren von dynamischen Arrays (mal abgesehen davon, dass das absolut lahm ist): Delphi hat dort einen RTL-Bug, der ein Memory-Leak verursacht. Das kannst Du umgehen, indem Du immer für mehrere Dateieinträge im Voraus Speicher reservierst

ausblenden Delphi-Quelltext
1:
SetLength(Result, Length(Result) + 1024);					


und dann einen separaten Index mitführst, welcher Eintrag als nächster zu schreiben ist (und nur vergrößerst, wenn Du über das Ende hinauskommen würdest).

Achja: Zusätzlichen Platz kannst Du sparen, wenn Du mit BackReferences arbeitest und nicht den vollständigen Pfad, sondern nur den Dateinamen und die Rückreferenz auf das Verzeichnis speicherst.

3. Reservieren eines unbenötigten Eintrags ...
Du reservierst immer erst den Speicher für einen Eintrag, schreibst diesen (irgendwann vielleicht mal) holst dann aber noch einen neuen gleich: Das richtigere Verhalten wäre Einträge dann zu alloziieren, wenn sie benötigt werden ...

Schau Dir mal die DriveUtils an (gibt's hier irgendwo im Forum)...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Marco D.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2750

Windows Vista
Delphi 7, Delphi 2005 PE, PHP 4 + 5 (Notepad++), Java (Eclipse), XML, XML Schema, ABAP, ABAP OO
BeitragVerfasst: So 28.05.06 13:36 
Reicht es nicht, MD5-Hashes der Dateien zu berechnen, abzuspeichern und dann zu vergleichen? :roll:

_________________
Pascal keeps your hand tied. C gives you enough rope to hang yourself. C++ gives you enough rope to shoot yourself in the foot
starsurfer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 334

Win 95, Win 98, Win XP, Win Vista, Linux
D5 Enterprise ,D2005, D6 Personal, Visual C++ Express 2005, C++ Builder 6 E, Dev-C++
BeitragVerfasst: So 28.05.06 14:35 
ahh thx für die Tipps :D

jetzt braucht er nich mal 5 MB RAM

akt. Version:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
function SucheDateien(pfad,Maske:string;Unterordner:bool):TDateien;
var c:char;
procedure suchen(const Pfad:string);
var SR: TSearchRec;
begin
  if FindFirst(Pfad + Maske, faAnyFile - faDirectory, SR) = 0 then
  try
    repeat
      if akt_eintrag>length(result) then
         begin
         setlength(result,length(result)+1024);
         end;
      result[akt_eintrag-1].pfad:=pfad + SR.Name;
      result[akt_eintrag-1].size:=sr.Size;
      inc(akt_eintrag);
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;

  if Unterordner then begin
    if FindFirst(pfad + '*.*', faAnyFile, SR) = 0 then
    try
      repeat
        if ((SR.attr and faDirectory) = faDirectory) and
           (SR.Name <> '.'and (SR.Name <> '..'then
          suchen(pfad + SR.Name + '\');
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
  end;

end;

das mit dem Pfad abkürzen bau ich noch ein.

@Marco D.
das werd ich wahrscheinlich auch noch mit ein bauen. Aber reichen tut MD5 nicht(als einziges). ich will ja später anzeigen lassen ob Datein neu hinzu gekommen/gelöscht/verändert wurden. Inklusive Änderungsdatum,Zeit,Größenveränderung....

_________________
GEIZ IST GEIL! - Ihr Sozialamt
Marco D.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2750

Windows Vista
Delphi 7, Delphi 2005 PE, PHP 4 + 5 (Notepad++), Java (Eclipse), XML, XML Schema, ABAP, ABAP OO
BeitragVerfasst: So 28.05.06 14:46 
user profile iconstarsurfer hat folgendes geschrieben:

jetzt braucht er nich mal 5 MB RAM

BenBE ist halt unschlagbar 8)
user profile iconstarsurfer hat folgendes geschrieben:

@Marco D.
das werd ich wahrscheinlich auch noch mit ein bauen. Aber reichen tut MD5 nicht(als einziges). ich will ja später anzeigen lassen ob Datein neu hinzu gekommen/gelöscht/verändert wurden. Inklusive Änderungsdatum,Zeit,Größenveränderung....

Ok, aber ich würde den reinen Vergleich über die Hashes machen. Danach kannst du ja falls nötig den Rest auslesen.

_________________
Pascal keeps your hand tied. C gives you enough rope to hang yourself. C++ gives you enough rope to shoot yourself in the foot
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 28.05.06 14:50 
Der Datentyp Bool ist zwar ein Wahrheitswert, jedoch sollte immer Boolean verwendet werden (BOOL ist ein WinAPI-Typ und hat eine etwas andere Semantik als Boolean). Falsch ist es aber (abgesehen vom zusätzlichen Speicherverbrauch) nicht ...

Weiterhin optimieren könntest Du z.B. so hier:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
  try
    repeat
      if akt_eintrag>High(result) then
      begin
        setlength(result,length(Result)+1024);
      end;
      result[akt_eintrag].pfad:=pfad + SR.Name;
      result[akt_eintrag].size:=sr.Size;
      inc(akt_eintrag);
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;


In diesem Fall müsste akt_eintrag mit 0 initialisiert werden und Result mit SetLength(Result, 0);. Das spart noch mal ein paar Rechenzyklen ...

P.S.: Am Ende solltest Du Result noch auf die nötigen Einträge verkleinern:
ausblenden Delphi-Quelltext
1:
SetLength(Result, akt_eintrag);					

Sonst ist da wieder zu viel Speicher belegt *g*

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
starsurfer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 334

Win 95, Win 98, Win XP, Win Vista, Linux
D5 Enterprise ,D2005, D6 Personal, Visual C++ Express 2005, C++ Builder 6 E, Dev-C++
BeitragVerfasst: So 28.05.06 15:14 
Thx, habs auch geändert... :)
user profile iconBenBE hat folgendes geschrieben:

P.S.: Am Ende solltest Du Result noch auf die nötigen Einträge verkleinern:
ausblenden Delphi-Quelltext
1:
SetLength(Result, akt_eintrag);					

Sonst ist da wieder zu viel Speicher belegt *g*


aja daran hab ich schon gedacht, allerdings muss das
SetLength(Result, akt_eintrag+1); heisen.... sonst schneidet es die letzte Datei weg.

so werd dann mal weiter machen.....

//Edit: seh grade das das +1 falsch ist.
Hing mit meiner weiteren Bearbeitung zusammen die noch auf alte ausgelegt war :oops:

_________________
GEIZ IST GEIL! - Ihr Sozialamt
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 28.05.06 15:20 
user profile iconstarsurfer hat folgendes geschrieben:
allerdings muss das
SetLength(Result, akt_eintrag+1); heisen.... sonst schneidet es die letzte Datei weg.


Ne *g* Da Du in akt_eintrag immer das nächste freie Feld stehen hast, haut das so hin.

Beispiel:
Akt_Eintrag = 0 --> 0 Einträge --> Result wird 0 Elemente groß --> keiner weggeschnitten
Akt_Eintrag = 1 --> Eintrag 0 enthält eine Datei --> SetLength(Result, 1) behält genau diesen einen Eintrag bei --> keiner abgeschnitten

Voraussetzung dafür ist, das akt_eintrag IMMER auf den nächsten freien Speicherplatz im Array zeigt.

In der Hinsicht weiß ich, was ich mach ;-)

Die Dinge zwecks Speed-Optimierung gehören aber IMHO eher unter Algo&Opti, weshalb ich hier mal drauf verzichte ^^ (BTW: Da lässt sich übrigens einiges rausholen, wenn man weiß, wo man ansetzen kann. (Arrays von Delphi sind nämlich arschlahm ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: So 28.05.06 17:03 
Hallo,

ich bin reineweg begeistert vom FastMemorymangager FastMM4.
Sagenhaft.
Ich habe die erste Version normal getestet und erhalte bei 513 MB ein out of memory error nach 2 Minuten.
Mit Einbau von FastMM4 in die uses der *.dpr -Datei nach 3 Sekunden das Ergebnis von 259790 *.htm* Dateien, maximaler Speicherbedarf 19,700 Mb zum Ende 19,384 Mb das ist doch ein sehr ueberzeugendes Ergebnis, das man trotz schlechter Programmierung, eine gute Laufzeit hinbekommen kann.

Gruss Horst
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
program Project1;

{$APPTYPE CONSOLE}

uses
  FastMM4,
  SysUtils;

type
  TDateien = record
   pfad:array of string;
   size:array of integer;
   end;
var
  TestDat : TDateien;

function SucheDateien(pfad,Maske:string;Unterordner:boolean):TDateien;
  procedure suchen(const Pfad:string);
  var
    SR: TSearchRec;
  begin
    if FindFirst(Pfad + Maske, faAnyFile - faDirectory, SR) = 0 then
    try
      repeat
        result.pfad[length(result.pfad)-1]:=pfad + SR.Name;
        result.size[length(result.size)-1]:=sr.Size;
        setlength(result.pfad,length(result.pfad)+1);
        setlength(result.size,length(result.size)+1);
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
  if Unterordner then begin
    if FindFirst(pfad + '*.*', faAnyFile, SR) = 0 then
    try
      repeat
        if ((SR.attr and faDirectory) = faDirectory) and
           (SR.Name <> '.'and (SR.Name <> '..'then
          suchen(pfad + SR.Name + '\');
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
  end;
end;

begin
try
  setlength(result.pfad,1);
  setlength(result.size,1);
  suchen(pfad);
except
  writeln('Fehler beim Suchen');
end;//try
end;//sucheDaeteien

begin
  TestDat := SucheDateien('C:','*.htm*',true);
  writeln(length(Testdat.pfad));
  readln;
end.