Autor Beitrag
bbfan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 09.04.05 11:35 
Hallo!

Ich habe eine eigene Class gebaut. Ganz simple...

Nun erzeuge ich über eine Schleife Objects von dieser Class und muss feststellen, dass mein Speicher sehr schnell vollläuft.
Ich habe zum Test dafür gesorgt, dass das erzeugte Object nicht mit Daten gefüllt wird. Der Speicher läuft trotzdem sehr schnell zu. Warum?

Gib es nicht Speicher fressende Objects?

Die erzeugten Objekte werden in einem dynamischen Array of CUFile abgelegt.

So fängt meine Class an:

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:
unit CUFile;

interface

uses
  Classes,SysUtils;
type
  TFile = Class  
  private
    sFilename : String;
    sSize : Int64;
    sPath : String;
    sPathFilename : String;
    sTime : Integer;
    sAttr : Integer;
  Public
    Constructor create();
  Published
    property Filename : String read sFilename write sFilename;
    property Size : Int64 read sSize write sSize;
    property Path : String read sPath write sPath;
    property Time : Integer read sTime write sTime;
    property Attr : Integer read sAttr write sAttr;
    property PathFilename : String read sPathFilename write sPathFilename;
    procedure importFromSearchRec(src:TSearchRec; FilePath:String);
    procedure importFromTFile(src:TFile);
    function formatedTime():String;
  end;


implementation
.....


Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt.
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: Sa 09.04.05 11:43 
Wenn ich dich Frage nun richtig verstehe würde ich sagen:
Die Felder einer Klasse (ob nun intialisiert oder nicht), bestimmen den Maßanteil für die Größe einer entsprechenden Instanz (Pointer- und virtuelle Pointer-Tabellen und ähnliches mal ausgelassen). Bedeutet also, hast du eine Klasse mit 2 Integer wird (in gängigen Archittekturen) 2*4 = 8 Bytes pro Objekt belegt.

Ich hebe aber das Gefühl, dass ich deine Frage dennoch falsch verstanden habe...

_________________
Carpe Noctem
bbfan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 09.04.05 12:14 
An für sich nicht... geht schon in die richtige Richtung.

Mich wundert es nur, dass der Speicher dermassen schnell zu geht, das ich dabei zuschauen kann.

Vielleicht liegt es am dynamischen array.... vielleicht sollte ich alles in ein TList packen.

Vom Prinzip her habe ich eien rekursive schleife, die die Dateien aus Verzeichnissen ausliest. Die Daten je Datei werden (s. Code oben) einem CUFile Object abgelegt.
Und die einzelnen CUFile Objecte gehen dann in ein dym. Array rein.

Frage: Wie bekomme ich das speicherschonender hin? Es kommen schon mehrere 1000 Dateien zusammen...
bbfan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 09.04.05 14:52 
ich habe eine Lösung gefunden: Mit TList arbeiten und Records.
Allerdings warne ich davor den TList.sort Befehl zu nutzen. Der sortiert nicht richtig.
Benutzt eurer eigene QuickSort Procedure und alles wird gut!
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: Sa 09.04.05 22:20 
Also willst du nun statt Objekten (Referenzen) die Zeiger von Record-Variablen dort ablegen? Wenn die Methoden deiner Objekte nicht unbedingt sein müssen, sparst du damit ja etwas (ich galub der eine oder andere wird es als "unsauberer" empfinden, da nicht OOP).

Ich hab noch nie Probleme mit dem Sort einer TList gehabt (ist doch auch ein Quicksort). Du musst nur eine entsprechende Compare-Funktion übergeben, dann sollte es klappen.

_________________
Carpe Noctem
Keldorn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 2266
Erhaltene Danke: 4

Vista
D6 Prof, D 2005 Pro, D2007 Pro, DelphiXE2 Pro
BeitragVerfasst: Sa 09.04.05 22:50 
user profile iconbbfan hat folgendes geschrieben:


Mich wundert es nur, dass der Speicher dermassen schnell zu geht, das ich dabei zuschauen kann.

Vielleicht liegt es am dynamischen array.... vielleicht sollte ich alles in ein TList packen.

Tlist hat auch ein dynam. array als grundlage. So wie du dein Problem beschreibst, vermute ich eher, das du innerhalb deiner Schleife jedesmal setlength(array,größe_des_array+1) aufrufst und dein array jedesmal um eins erweitest ?

Mfg Frank

_________________
Lükes Grundlage der Programmierung: Es wird nicht funktionieren.
(Murphy)
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: Sa 09.04.05 23:10 
Wirkt sich dieses 1-Increment-Capacity-Management nicht eher nachteilig auf den Prozessezor denn auf den Speicher aus?

_________________
Carpe Noctem
Keldorn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 2266
Erhaltene Danke: 4

Vista
D6 Prof, D 2005 Pro, D2007 Pro, DelphiXE2 Pro
BeitragVerfasst: So 10.04.05 08:33 
Das ist auch schon mehrfach hier diskutiert wurden. Eine gute Erklärung findet sich auch hier

Mfg Frank

_________________
Lükes Grundlage der Programmierung: Es wird nicht funktionieren.
(Murphy)
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: So 10.04.05 12:20 
Zitat:

...oder man arbeitet mit einem großen Delta-Wert und einer RealLength Variable, die die effektive Länge des Strings / Arrays enthält.


Ich darf annehmen, damit sind Capacity und Count in Tlist und TObjectList gemeint? Sprich also die Realisierung eines Standard-Vectors für Pointer?

_________________
Carpe Noctem
Keldorn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 2266
Erhaltene Danke: 4

Vista
D6 Prof, D 2005 Pro, D2007 Pro, DelphiXE2 Pro
BeitragVerfasst: So 10.04.05 13:21 
nein,

eher so (Pseudocode):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
Var arr:array of Tirgendwas;
    Laenge:integer;
begin
  laenge:=-1;
 
  while irgendetwas do
   begin
     //wenn notwendig, array um z.B. 100 neue Einträge erweitern      
     if laenge>=length(arr) then setlenght(arr,length(arr)+100); 
     inc(laenge);
     //Array-Eintrag füllen
     arr[laenge]:=blablabla;
   end
  //und zum schluß auf die richtige Größe setzen
  setlenght(arr,laenge); 
end;

_________________
Lükes Grundlage der Programmierung: Es wird nicht funktionieren.
(Murphy)
Tilo
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1098
Erhaltene Danke: 13

Win7 geg. WInXP oder sogar Win98
Rad2007
BeitragVerfasst: Mo 11.04.05 14:00 
Wenn das dynamische Array nur zum Auflisten der Elemente führt, rate ich von dynamischen Arrays ab.
Nihm lieber Pointer.

z.b:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
PTrec:^Trec;
Trec = reorcd
 elementA:irgendeeinTyp;
 elementB:irgendeeinTyp;
 elementC:irgendeeinTyp;
 ....
 nextRec:PTrec;
end;

nextrec beinhaltet dann die Speicheradresse des nächsten Elements.
Vorteil gegenüber Dynarray:
- schneller
- schmiert nicht bei sehr vielen Elmenten ab
Keldorn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 2266
Erhaltene Danke: 4

Vista
D6 Prof, D 2005 Pro, D2007 Pro, DelphiXE2 Pro
BeitragVerfasst: Mo 11.04.05 14:13 
user profile iconTilo hat folgendes geschrieben:
Vorteil gegenüber Dynarray:
- schneller

aber nur, wenn du dich von einem Element zum Nächsten hangelst. Was ist, wenn du 1000 Einträge hast, und den 1. 300. und 700. eintrag auslesen möchtest? Dann wird dein Geschwindigkeitsvorteil schnell dahin sein.

user profile iconTilo hat folgendes geschrieben:
- schmiert nicht bei sehr vielen Elmenten ab

Das mußt du genauer erläutern. wieso soll ein dyn. array bei sehr vielen Elementen "abschmieren"?

Mfg Frank

_________________
Lükes Grundlage der Programmierung: Es wird nicht funktionieren.
(Murphy)
Tilo
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1098
Erhaltene Danke: 13

Win7 geg. WInXP oder sogar Win98
Rad2007
BeitragVerfasst: Mo 11.04.05 22:05 
@Keldorn
ich hatt bei meinen Primgenerator das Problem, dass wenn ich am Anfang das Array auf ein hohes Index eingestellt hab ( 200000 oder noch 1, 2 Nullen) das das Programm abgebrochen wurde. Bei einem statischen Array dagegen kann ich ohne Probleme wesentlich höhere Indexe nehmen, Nachteil: Imenser Speicherbedarf
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Di 12.04.05 15:49 
Kleine Anmerkung: Mit TFile.Create sollte gleich viel Speicher alloziert werden wie die Grösse des äquivalenten Records(+4). (Eine simple Klasse ist ja von der Idee her nichts anderes als ein record mit einer Ansammlung von Funktionen)

Übrigens: Wenn es dir um jedes Byte geht, mach ein dynamisches "Array of TFile", wobei TFile ein packed record ist. (PS: Es gibt auch packed classes. (Scheint aber nicht zu funktionieren))

//Edit: Änderungen im Text


Zuletzt bearbeitet von delfiphan am Di 12.04.05 23:24, insgesamt 1-mal bearbeitet
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 12.04.05 17:27 
user profile icondelfiphan hat folgendes geschrieben:
PS: Es gibt auch packed classes

:shock: Das musst du mal bitte näher erläutern..!

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Di 12.04.05 18:56 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// Schnell aber gross (8 Bytes)
  TTest = class
   B: Byte;
   I: Integer;
  //...
  end;

// Klein aber langsam (5 Bytes)
  TTest = packed class 
   B: Byte;
   I: Integer;
  //...
  end;
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 12.04.05 23:02 
Hm.. kompilieren tut es (war mir neu, dass das geht), aber die Größe ändert sich trotzdem nicht.. Erstens hast du vergessen, dass alle Klassen intern automatisch von TObject abgeleitet werden und von daher automatisch schon mind. 4 Bytes groß sind, und zweitens sind bei mir beide Klassen 12 Bytes groß. Aber egal - packed classes würden IMHO sowieso keinen Sinn machen..!

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Di 12.04.05 23:10 
Stimmt und stimmt. Sind beides mal 12 Bytes. Naja... Das packed ist wohl für Rückwärtskompatibilität oder so.
Gruss
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: Di 12.04.05 23:22 
Ich kannte packed immer nur im Zusamenhang mit Arrays (wo sie dort den gleichen Sinn erfüllen sollen). Ist dies auch redundant geworden?

_________________
Carpe Noctem
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mi 13.04.05 00:06 
Im Zusammenhang mit Arrays weiß ich es nicht genau, da hab ich es auch noch nie verwendet. Wo es aber durchaus noch Verwendung findet und auch nicht redundant ist, ist bei Records. zB:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
type
  // dieser Record ist 4 Bytes groß
  TMyRecord = record
    a: Byte;
    b: Word;
  end;

  // dieser Record ist 3 Bytes groß
  TMyPackedRecord = packed record
    a: Byte;
    b: Word;
  end;

Der Grund, warum der erste Record um 1 Byte größer ist liegt darin, dass der Compiler versucht die Felder an Word oder Double-Word Grenzen auszurichten, da dann schneller darauf zugegriffen werden kann. Die Ausrichtung ist abhängig von der Größe des Feldes. Ein Word (2 Bytes) wird an einer Word-Grenze ausgerichtet, sollte also an einer Stelle im Speicher stehen, die durch 2 teilbar ist. Ein DWord (4 Bytes) hingegen an einer Double-Word-Grenze, also an einer Stelle, die durch 4 teilbar ist. Bei einzelnen Bytes ist es logischerweise egal..
Liegt ein DWord nun an einer Stelle die zwar durch 2, aber nicht durch 4 teilbar ist, so kann der Wert nicht auf einmal gelesen werden, sondern muss durch 2 Speicherzugriffe gelesen werden - nämlich als 2 Words (da ja die Adresse durch 2 teilbar ist). Im schlimmsten Fall muss zum Lesen eines DWords also 4 mal auf den Speicher zugegriffen werden.
Um dies zu verhindern, versucht der Compiler die Records eben zu optimieren, indem er Filler-Bytes einfügt um die Felder an den entsprechenden Speichergrenzen auszurichten. Durch geschicktes Anordnen kann man da aber auch selbst optimieren. zB:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
type
  // ungeschickt - 6 Bytes groß
  TMyRecord = record
    a: Byte;
    b: Word;
    c: Byte;
  end;

  // geschickter - nur 4 Bytes groß
  TMyPackedRecord = packed record
    a: Byte;
    c: Byte;
    b: Word;
  end;

Die Records enthalten beide dieselben Felder - nur in unterschiedlichen Reihenfolgen.

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!