Autor |
Beitrag |
starsurfer
      
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++
|
Verfasst: 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
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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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)...
_________________ 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.
      
Beiträge: 2750
Windows Vista
Delphi 7, Delphi 2005 PE, PHP 4 + 5 (Notepad++), Java (Eclipse), XML, XML Schema, ABAP, ABAP OO
|
Verfasst: So 28.05.06 13:36
Reicht es nicht, MD5-Hashes der Dateien zu berechnen, abzuspeichern und dann zu vergleichen? 
_________________ 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 
      
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++
|
Verfasst: So 28.05.06 14:35
ahh thx für die Tipps
jetzt braucht er nich mal 5 MB RAM
akt. Version:
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.
      
Beiträge: 2750
Windows Vista
Delphi 7, Delphi 2005 PE, PHP 4 + 5 (Notepad++), Java (Eclipse), XML, XML Schema, ABAP, ABAP OO
|
Verfasst: So 28.05.06 14:46
starsurfer hat folgendes geschrieben: |
jetzt braucht er nich mal 5 MB RAM
|
BenBE ist halt unschlagbar
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.
_________________ 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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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*
_________________ 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 
      
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++
|
Verfasst: 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 
_________________ GEIZ IST GEIL! - Ihr Sozialamt
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 ...
_________________ 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
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: 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
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. |
|
|
|