Entwickler-Ecke
Dateizugriff - Alle Dateien auf C: suchen - 400 MB RAM Verbrauch?
starsurfer - So 28.05.06 12:08
Titel: Alle Dateien auf C: suchen - 400 MB RAM Verbrauch?
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
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?
BenBE - 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:
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
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)...
Marco D. - So 28.05.06 13:36
Reicht es nicht, MD5-Hashes der Dateien zu berechnen, abzuspeichern und dann zu vergleichen? :roll:
starsurfer - So 28.05.06 14:35
ahh thx für die Tipps :D
jetzt braucht er nich mal 5 MB RAM
akt. Version:
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....
Marco D. - So 28.05.06 14:46
starsurfer hat folgendes geschrieben: |
jetzt braucht er nich mal 5 MB RAM
|
BenBE ist halt unschlagbar 8)
starsurfer 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.
BenBE - 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:
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:
Delphi-Quelltext
1:
| SetLength(Result, akt_eintrag); |
Sonst ist da wieder zu viel Speicher belegt *g*
starsurfer - So 28.05.06 15:14
Thx, habs auch geändert... :)
BenBE hat folgendes geschrieben: |
P.S.: Am Ende solltest Du Result noch auf die nötigen Einträge verkleinern:
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:
BenBE - So 28.05.06 15:20
starsurfer 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 ...
Horst_H - 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 [
http://sourceforge.net/project/showfiles.php?group_id=130631] 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
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;end; begin TestDat := SucheDateien('C:','*.htm*',true); writeln(length(Testdat.pfad)); readln; end. |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!