Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 18, 2025 11:55

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 25 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
 Betreff des Beitrags: Dynamische Arrays löschen
BeitragVerfasst: Mo Nov 07, 2005 20:15 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jul 17, 2002 12:07
Beiträge: 976
Wohnort: Tübingen
Hi,
und zwar plagt mich grad folgendes Problem: Ich habe ein dynamisches Array (array of ...), in das ich beim laden meines Programms Daten hineinschreibe. Die Größe lege ich per SetLength fest. Soweit so gut. Nun muss ich aber im Laufe des Programms die Daten wieder ändern, bzw sie werden neu von der Festplatte geladen. Ich habe nun immer gedacht, dass man den Speicher, den das Array belegt, mit SetLength(FooArray, 0) wieder freigeben kann. Dem ist aber nicht so. Also wird der Speicher, den mein Programm belegt, immer größer, was natürlich nicht sehr schön ist. Deshalb die Frage an euch, wie gebe ich den Speicher richtig frei?
Schonmal Danke.

PS:
Ich schreibs mal als Pseudocode, wie ichs bis jetzt gemacht hab:

Code:
  1.  
  2. var
  3.  Foo: Array of record
  4.                          bar: Integer;
  5.                          Foobar: Gluint;
  6.                          ...
  7.                      end;
  8.  
  9. procedure LoadData;
  10. begin
  11. ... //Daten von der Festplatte auslesen
  12.  
  13. SetLength(Foo, 666);
  14. for i:= 0 to 665 do
  15.  begin
  16.   Foo[i].bar:= xxx;
  17.   ....
  18.  end;
  19. end;
  20.  
  21. später:
  22.  
  23. procedure LoadData2;
  24. begin
  25. ... //Daten von der Festplatte auslesen
  26.  
  27. SetLength(Foo, 0);
  28.  
  29. SetLength(Foo, 999);  //Den Zahlenwert lese ich natürlich auch aus!
  30. for i:= 0 to 998 do
  31.  begin
  32.   Foo[i].bar:= xxx;
  33.   ....
  34.  end;
  35. end;
  36.  

_________________
"Du musst ein Schwein sein in dieser Welt, sangen die Prinzen, das ist so 1.0. Du musst auf YouTube zeigen, dass dir dein Schweinsein gefällt, das ist leuchtendes, echtes Web 2.0."
- Hal Faber

Meine Homepage: http://laboda.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Nov 07, 2005 20:22 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Apr 25, 2005 17:51
Beiträge: 464
laut Doku nil setzen oder finalize aufrufen, sodass das Betriebssystem den speicher dann freigeben kann, was auch immer das heißen mag ...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Nov 07, 2005 20:56 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Das SetLength müßte eigentlich ausreichen, aber der Delphi Speichermanager gibt den Speicher nicht immer sofort an Windows zurück. Daher kann man nicht von den Werten für das Programm ausgehen. Wenn man wirklich wissen will wieviel Speicher belegt ist muß man sich HeapStatus (oder so ähnlich) ansehen.
Aber für solche Zwecke sind Listen besser.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Nov 07, 2005 21:05 
Offline
DGL Member

Registriert: Fr Dez 19, 2003 14:27
Beiträge: 107
Wohnort: Indianapolis, USA
Wollte ich auch gerade schreiben. Falls das noch aktuell ist:
http://info.borland.com/techpubs/delphi/delphi5/oplg/memory.html
Denn reservier0t Delphi den Speicher von Windows in 1MB chunks und gibt die erst wieder zurueck wenn so ein zusammenhaengender 1MB Block frei wird. Wenn du also dynamische Arrays oft in der Groesse aenderst wird wahrscheinlich der Speicher fragmentiert und deshalb nicht sofort wieder frei gegeben.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 09:02 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jul 17, 2002 12:07
Beiträge: 976
Wohnort: Tübingen
@Tokter: Es stimmt schon, dass ich oft die Größe ändere, aber bevor ich die Größe ändere, ruf ich eigentlich immer SetLength 0 auf.
@Pellaeon: Das mit nil hab ich schon ausprobiert, das funtioniert nicht. finalize hab ich noch ned ausprobiert, weil hier schon darüber geredet wurde, ich aber ned ganz mitkomm. Kann mir das vielleicht jmd zusammenfassen?
@Lars: Das mit Listen wär ne Alternative, aber seh ich das als Notnagel, da ich weite Teile meines (ansonsten funktionierenden) Codes ändern müsste.

Gibt es denn vielleicht einen globalen Befehl, der allen Speicher, der in Delphi freigegeben wurde, auch für Windows freigibt?

_________________
"Du musst ein Schwein sein in dieser Welt, sangen die Prinzen, das ist so 1.0. Du musst auf YouTube zeigen, dass dir dein Schweinsein gefällt, das ist leuchtendes, echtes Web 2.0."
- Hal Faber

Meine Homepage: http://laboda.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 14:50 
Offline
DGL Member

Registriert: Fr Dez 19, 2003 14:27
Beiträge: 107
Wohnort: Indianapolis, USA
State 1:
Code:
  1.  
  2. AAAAAAAAAAAAAAAAAOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
  3. ^Dein Array      ^Irgend ein Objekt
  4.  


State 2: Du vergroesserest dein Array:
Code:
  1.  
  2. NNNNNNNNNNNNNNNNNOOOOOOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANNN
  3.                ^Dein Array
  4.  


Es passt da nicht mehr rein und muss vom Memory Manager wo anders platziert werden. So wird
der Speicher fragmentiert. Da hilft kein SetLength(0), damit gibst du den Speicher nur an den Memory
Manger zurueck und hast ihn wiede zur verfuegung fuer andere Objekte und Arrays (je nach dem wo sie reinpassen).
Haeufig ein dynamisches Array in der Groesse zu aendern ist meist keine gute Idee da es dann staendig im Speicher rumkopiert wird -> langsam.
Wenn du weisst wie gross es maximal werden kann dann leg doch ein Array ueber diese maximale Groesse an und merk dir wieviele gueltige Eintraege es da drin hat. Oder wie schon gesagt, nimm eine Liste...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 16:28 
Offline
DGL Member

Registriert: Sa Jan 22, 2005 21:10
Beiträge: 225
Tokter hat recht, es is wahrscheinlich Heap-Fragmentation. Allerdings tritt das nur auf, wenn du dein Array sehr oft vergrößerst. Bei sowas wie
Code:
  1.  
  2. SetLength(Vertices, 0);
  3. SetLength(TexCoords, 0);
  4. while NOT eof(myfile) do
  5. begin
  6.         SetLength(Vertices, Length(Vertices)+1);
  7.         BlockRead(myFile, Vertices[High(Vertices)], SizeOf(Vertices[High(Vertices)]));
  8.         SetLength(TexCoords, Length(TexCoords)+1);
  9.         BlockRead(myFile, TexCoords[High(TexCoords)], SizeOf(TexCoords[High(TexCoords)]));
  10. end;
  11.  

ist Heapfragmentation natürlich vorprogrammiert (hoho, habt ihr das Wortspiel gesehen? :wink: ). Aber wenn du es nur ein paar mal machst, dürfte es eigentlich kein Prob sein, weil der Speicher für kleinere Objekte, solange sie nicht lokal deklariert sind, nicht verloren geht. Also sowas wie in deinem Beispielprog ist überhaupt kein Prob (666 x 8 Byte + 999 x 8 Byte = 13320 Byte).

Zu Listen würde ich auch nicht unbedingt raten. Das hängt von deinem Anwendungsfall ab. Für mich sah das jetzt so aus, als wären die einzelnen Records eher klein, und da dann 2 x 32 Bit Pointer reinhauhen, würde den Speicherbedarf mal eben verdoppeln. Wenns wirklich viel Kleinkram ist, würde ich es vielleicht auf mehrere Arrays aufteilen, und mir bei Bedarf ein neues Array mit fester Größe dazuholen oder freigeben.
Was willst du denn genau machen?

AL

_________________
[18:30] tomok: so wie ich das sehe : alles. was nich was anderes ist als nen Essay ist nen Essay

hi, i'm a signature viruz, plz set me as your signature and help me spread :)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 16:56 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 14, 2004 18:56
Beiträge: 804
Wohnort: GER/OBB/TÖL-WOR/Greiling
ich packe das immer in eine Klasse bzw. implemetiere es im prog so, dass ich add(array,value) aufrufe, um etwas hinzuzufügen. add sieht dann ungefähr so aus:

Code:
  1.  
  2. procedure MyRecordAdd(var varray:TMyRecords, Value: TMyRecord);
  3. var newlen:integer;
  4. begin
  5. // mem mgmt
  6. if (noccupied = length(varray)) then
  7.   begin
  8.    newlen := ceil(length(varray)*1.72);
  9.    setlength(varray,newlen);
  10.   end;
  11.  
  12. //assignment
  13. varray[noccupied] := Value;
  14. Inc(nOccupied);
  15. end;
  16.  


noccupied muss irgendwo definiert sein und ist die anzahl belegter stellen im array.
1.72 kommt von irgendeinem Thread in der DP, in dem mal davon die rede war, dass man das array am besten um 172% ergrößern sollte, weil das durchschnittlich der beste Wert sei.

_________________
Bild

"User Error. Replace User and hit Continue."


Zuletzt geändert von luketheduke am Di Nov 08, 2005 16:57, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 16:56 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jul 17, 2002 12:07
Beiträge: 976
Wohnort: Tübingen
@AL: Ich habe eine Unit, die mir Geometriedaten einer Szene aus verschiedenen Formaten auslesen kann (bis jetzt nur 3ds) und alle möglichen Informationen darüber kapselt. Dazu kommen ein paar Berechnungen, wie Normalen, Tangenten etc. Es handelt also schon um große Datenmengen (zB Figuren mit 2000 Polygonen). Ich will im Laufe des Programms (es ist ein Spiel) diese Modelle mehrmals laden, da die Modelle sich ändern sollen.

Ich habe nun Testweise alles in eine Klasse gepackt, das sieht so aus:

Code:
  1.  
  2. type
  3.  Object3ds: class(TObject)
  4.   Vertices: array of Vertex3f;
  5.   TexCoords: array of Vertex3f;
  6.   ...
  7.   procedure Freigeben;
  8.  end;
  9.  


Wenn ich nun die Prozedur \"Freigeben\" aufrufe, tut sich aber immer noch nix am Speicher:

Code:
  1.  
  2.  procedure Object3ds.Freigeben;
  3.  begin
  4.   SetLength(Vertices, 0);
  5.   SetLength(TexCoords, 0);
  6.  
  7.   Free;
  8.  end;
  9.  //So sieht auch Mesh.Destroy in Noeskas 3ds-Loader aus, nur dass statt dem free ein destroy da ist (Free empfiehlt mir die Delphi-Hilfe
  10.  

_________________
"Du musst ein Schwein sein in dieser Welt, sangen die Prinzen, das ist so 1.0. Du musst auf YouTube zeigen, dass dir dein Schweinsein gefällt, das ist leuchtendes, echtes Web 2.0."
- Hal Faber

Meine Homepage: http://laboda.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 17:01 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 14, 2004 18:56
Beiträge: 804
Wohnort: GER/OBB/TÖL-WOR/Greiling
wie bereits gesagt: eventuell behält der memory manager den speicher "nur sicherheitshalber" bzw. um ihn für spätere verwendung reserviert zu haben und evtl. überflüsige allocs vermeiden zu können.

Du solltest nur sehen, ob die Speicherbelegung bei mehrmaligen freigeben und neu erzeugen von objekten steigt. Das ist der Knackpunkt.
//Edit: steht ja im ersten post :roll:

_________________
Bild

"User Error. Replace User and hit Continue."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 18:19 
Offline
DGL Member

Registriert: Sa Jan 22, 2005 21:10
Beiträge: 225
Zitat:
Ich will im Laufe des Programms (es ist ein Spiel) diese Modelle mehrmals laden, da die Modelle sich ändern sollen.

Also so ne Art Animation mit wahrscheinlich mehr als 15 Modellen die Sekunde...

Naja, Listen kannste da natürlich vergessen. Dann machs entweder so wie Luketheduke es beschrieben hat, oder was Tokter meinte: Du gehst erstmal alle Modelle durch und guckst, wie viele Vertices, Indices, ... das Größte hat (natürlich nach Vertices, TexCoords, Indices, ... getrennt). Und dann richtest du die Arrays nach den Werten ein.

_________________
[18:30] tomok: so wie ich das sehe : alles. was nich was anderes ist als nen Essay ist nen Essay

hi, i'm a signature viruz, plz set me as your signature and help me spread :)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 18:32 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jul 17, 2002 12:07
Beiträge: 976
Wohnort: Tübingen
AL hat geschrieben:
Ich will im Laufe des Programms (es ist ein Spiel) diese Modelle mehrmals laden, da die Modelle sich ändern sollen.

Also so ne Art Animation mit wahrscheinlich mehr als 15 Modellen die Sekunde...

Nein, es ist so ein Geschicklichkeitsspiel mit Lehrern (für unsere Schule). Eine Runde dauert 90 sekunden. in jeder neuen Runde soll per Zufall ein Lehrermodell aus ner Reihe ausgewählt und geladen werden, der dann 90 sekunden lang angezeigt wird. Gleich alle Modelle zu laden, ist viel zu speicherhungrig.

_________________
"Du musst ein Schwein sein in dieser Welt, sangen die Prinzen, das ist so 1.0. Du musst auf YouTube zeigen, dass dir dein Schweinsein gefällt, das ist leuchtendes, echtes Web 2.0."
- Hal Faber

Meine Homepage: http://laboda.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 18:34 
Offline
DGL Member

Registriert: Mi Dez 15, 2004 20:36
Beiträge: 454
Wohnort: Wien, Österreich
Zitat:
Gibt es denn vielleicht einen globalen Befehl, der allen Speicher, der in Delphi freigegeben wurde, auch für Windows freigibt?

Dann musst du halt win32 API benutzen und nicht heap memory manager.

_________________
"Meine Mutter sagt : 'Dumm ist der, der Dummes tut'." - Forrest Gump


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 18:43 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Apr 25, 2005 17:51
Beiträge: 464
steig auf C++ um und nimm std::vector :wink:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Nov 08, 2005 22:46 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Zitat:
Dann musst du halt win32 API benutzen und nicht heap memory manager.

Pellaeon hat geschrieben:
steig auf C++ um und nimm std::vector :wink:


Das sind beides Hinweise die wenig hilfreich sind. Entscheidungen dieser größenordung trifft man bevor man Tasten drückt, nicht wenn schon 80% stehen. :?

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 25 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 16 Queries | GZIP : On ]