Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Freigabe von Objekten zeitaufwändig? (https://www.delphipraxis.net/153583-freigabe-von-objekten-zeitaufwaendig.html)

mjenke 9. Aug 2010 14:29

Freigabe von Objekten zeitaufwändig?
 
Hallo, alle miteinander!


Ich habe mal eine allgemeine Frage: Kann es sein, dass Objekte in Delphi wesentlich langsamer freigegeben als sie aufgebaut werden?

Ich frage aus folgendem Grund: In einer Anwendung, die mehrere hunderttausend-Objekte erzeugt, ist die Zeit, die für das Freigeben der Objekte verwendet wird, wesentlich (!!!!) höher als die Zeit, die benötigt wird, um sie aufzubauen. Die Verschachtelung der Objekte ist ziemlich diffizil, aber grundsätzlich ist es so, dass Objekte Unterobjekte besitzen, die wiederum n Unterobjekte besitzen etc. Die Verwaltung dieser Objekte ist baumähnlich.

Ich habe im Quelltext bereits alle Schrauben gedreht, die ich gefunden habe, um das Zerstören zu beschleunigen. Dennoch baut die Anwendung diese ganzen Objekte innerhalb weniger Minuten auf (3-4 Minuten), benötigt aber gut das 20fache an Zeit (70-80 Minuten), um sie wieder zu zerstören.

Handelt es sich dabei um ein allgemeines Phänomen, dass Speicherfreigabe kompliziertere Wege läuft, als Speicherallokation? Oder muss es doch an meinem Quellcode liegen?


Vielen Dank im Voraus!

Matthias

Bernhard Geyer 9. Aug 2010 14:34

AW: Freigabe von Objekten zeitaufwändig?
 
Mit oder Ohne Debug-Infos (Stichwort Speichercheck/FastMM)?
Genügend Speicher vorhanden (Auslagern von Programmspeicher durch Windows)?

himitsu 9. Aug 2010 14:41

AW: Freigabe von Objekten zeitaufwändig?
 
Womit werden die Unterobjekte verwaltet, bzw. wo werden deren Referenzen gespeichert?

mjenke 9. Aug 2010 15:35

AW: Freigabe von Objekten zeitaufwändig?
 
Hi, habe mal die Debug-Informationen ausgeschaltet, aber das ändert am Laufzeitverhaltn nichts.

@himitsu: Wie ist die Frage zu verstehen? Unterobjekte werden in einem Array Of TObject gespeichert.

Neutral General 9. Aug 2010 15:38

AW: Freigabe von Objekten zeitaufwändig?
 
Dein Programm braucht also 70-80 Minuten um sich zu beenden? :shock:

Dann kann da aber eigentlich irgendwas nicht stimmen... Eventuell solltest du dann deinen Code überdenken...

himitsu 9. Aug 2010 15:58

AW: Freigabe von Objekten zeitaufwändig?
 
OK, und wie werden dabei die Unterobjekte freigegeben?
Es wird doch nicht etwa jedes Objekt einzeln freigegeben, womöglich auch noch beginnend vom Anfang des Arrays und dann ständig jedes Objekt aus dem Array entfernt, die restlichen Einträge hochkopiert und dabei das Array stückchenweise verkleinert? :stupid:

Ohne zu wissen was dein Code macht, kann dir keiner helfen.

PS: bei meinem himXML hatte ich anfangs auch diesen Effekt, bis ich das Freigeben umgestellt hatte > alle Kind-Objekte im Destructor freigeben und dann das Array komplett löschen.

PSS: Warum nutzt du keine TObjektList?

taveuni 9. Aug 2010 16:01

AW: Freigabe von Objekten zeitaufwändig?
 
Zitat:

Zitat von mjenke (Beitrag 1040554)
@himitsu: Wie ist die Frage zu verstehen? Unterobjekte werden in einem Array Of TObject gespeichert.

Objekte in einer TObjectList würden Z.B. beim freigeben der Liste automatisch freigegeben.
Sind das visuelle Objekte?

Namenloser 9. Aug 2010 16:14

AW: Freigabe von Objekten zeitaufwändig?
 
Sind eventuell WideStrings in den Objekten? Ich habe die Erfahrung gemacht, dass das Freigeben von WideStrings ewig dauert.

Ansonsten: Ist ReportMemoryLeaksOnShutdown eingeschaltet? Wenn ja, schalte es mal aus, und schau, ob es dann schneller ist.

himitsu 9. Aug 2010 16:53

AW: Freigabe von Objekten zeitaufwändig?
 
ReportMemoryLeaksOnShutdown prüft nur am Ende des Programmes nach, ob noch was im Speichermanager liegt undzwar kurz vor Freigabe des Speichermanagers ... zu diesem Zeitpunkt wurden schon alle Objekte freigegeben (abgesehn von den Speicherleckt und diese würden dann auch angezeigt) ... dieses hat also keine Auswirkung zu diesem Zeitpunkt.

mjustin 9. Aug 2010 17:10

AW: Freigabe von Objekten zeitaufwändig?
 
Ja, wenn bei deren Freigabe Exceptions auftreten. Zwei Dinge würde ich testen:

a) gibt es Memory Leaks (-> das könnte auf Probleme beim eigentlich beabsichtigten Freigeben hinweisen)

b) wie werden Exceptions im Destruktor abgefangen, mit try except // nix end?

Namenloser 9. Aug 2010 17:37

AW: Freigabe von Objekten zeitaufwändig?
 
Zitat:

Zitat von himitsu (Beitrag 1040572)
ReportMemoryLeaksOnShutdown prüft nur am Ende des Programmes nach, ob noch was im Speichermanager liegt undzwar kurz vor Freigabe des Speichermanagers ... zu diesem Zeitpunkt wurden schon alle Objekte freigegeben (abgesehn von den Speicherleckt und diese würden dann auch angezeigt) ... dieses hat also keine Auswirkung zu diesem Zeitpunkt.

Oft werden Objekte aber beim Beenden des Programmes freigegeben, und es wirkt dann so, als würde dieser Vorgang lange dauern. Habe ich bei meinen Hashmap-Tests festgestellt, wo ich zwischenzeitlich mal zigtausend Memoryleaks hatte... (keine Sorge, jetzt sind es 0, falls jemand die mal benutzen möchte :stupid:)

himitsu 9. Aug 2010 17:40

AW: Freigabe von Objekten zeitaufwändig?
 
Wenn es lange dauert, dann liegt es nicht an ReportMemoryLeaks, es sei denn es muß ein rießiger Report erstellt werden.

Aber wie gesagt, ohne nähere Kenntnis zu diesem Projekt/Code, kann man nur wild rumraten.

NormanNG 9. Aug 2010 17:49

AW: Freigabe von Objekten zeitaufwändig?
 
Also ich habe durchaus die Erfahrung gemacht, das FastMM zum Beenden eines Programmes viel Zeit brauchen kann. Vor allem, wenn alle Debugging-Option aktiv sind. Dann werden u.U. alle Memoryblöcke auf korrekte Freigabe etc. geprüft und das kann - vor allem bei vielen zuvor benutzten Objekten - etwas dauern... unabhängig davon, ob der Code noch Fehler hat oder nicht.

Versuch es doch einfach mal FastMM mit komplett deaktivierten Debugoptionen einzubinden.

mjenke 11. Aug 2010 08:47

AW: Freigabe von Objekten zeitaufwändig?
 
@himitsu:

Natürlich habe ich anfangs auch mal brav immer das erste Objekt aus dem Array freigegeben, den Rest nach vorne verschoben und dann das Array verkleinert. Das hatte ich aber irgendwann selbst schon gefunden und mich fleißig geschämt :-D

Tatsächlich lief das Zerstören so ab, dass ich immer das letzte Objekt des Arrays zerstöre und dann das Array verkleinere.

Delphi-Quellcode:
while Last do Drop.Free;
Wobei Last eine Funktion einer Container-Klasse ist, von der sich all meine Container ableiten. Sie aktiviert den letzten Eintrag des Arrays (setzt einen Positionszeiger) und liefert True, wenn Einträge vorhanden sind, bzw. False wenn nicht.

Delphi-Quellcode:
function TMyContainer.Last: Boolean;
begin
  Result := Length ( FEntries ) > 0;
  if Result then FPosition := High ( FEntries );
end;
Drop liefert den aktiven Eintrag des Arrays und entfernt ihn gleichzeitig aus dem Array (wobei alle nachstehenden vorgezogen werden, was nicht allzu dramatisch ist, wenn ohnehin der letzte Eintrag aktiv war).

Delphi-Quellcode:
function TMyContainer.Drop: TObject;
var
  i, j: Integer;
begin
  Result := nil;
  if FPosition <> -1 then begin
    for i := FPosition to High ( FEntries ) do begin
      if i = FPosition then Result       := FEntries[i]
      else                 FEntries[i-1] := FEntries[i];
    end;
    SetLength ( FEntries, High ( FEntries ) );
    if     Length ( FEntries ) = 0 then FPosition := -1
    else if FPosition > High ( FEntries ) then FPosition := High ( FEntries );
  end;
end;
Auf Deine Anregung hin gebe ich in einer Prozedur DestroyAllObjects nun alle verwalteten Objekte frei und setze dann die Array-Größe auf 0.

Delphi-Quellcode:
procedure TMyContainer.DestroyAllObjects;
var
  i: Integer;
begin
  for i := 0 to High ( FEntries ) do FEntries[i].Free;
  SetLength ( FEntries, 0 );
  FPosition := -1;
end;
Das bringt mir immerhin mit meinen Testdaten eine Zeitersparnis von beinahe 30 Minuten ein. Statt der 75-80 Minuten brauchte meine Anwendung heute morgen nur 49 Minuten.

Vielen Dank für den Hinweis!!!

:D
Matthias

himitsu 11. Aug 2010 08:56

AW: Freigabe von Objekten zeitaufwändig?
 
Kleine Änderung, die gleich mal 40% einsprat :-D
(Welches bei wenigen freizugebenden Objekten ja fast garnicht auffällt, sich aber in der Masse schon fast als expotentielle Auswirkungen zeigt)

Nun müßte man nur noch die anderen Bremsen finden. :stupid:

jfheins 11. Aug 2010 09:00

AW: Freigabe von Objekten zeitaufwändig?
 
Das klingt jetzt ein bisschen nach Quick 'n Dirty programmierung, aber wenn die Anwendung beendet wird, brauche ich doch eigentlich den Speicherplatz gar nicht mehr freigeben?
ich weiß dass das ein Speicherleck ist, aber wenn die Anwendung danach eh von Windows weggefegt wird ... ? :twisted:

Etwas anderes ist es natürlich, wenn da irgendwelche Netzwerkressourcen oder so exklusiv gesperrt sind.

Okay, um auch etwas anderes ins Spiel zu bringen: Wäre es möglich, dass viel Speicher reserviert wird, aber nur wenig gebraucht? Sodass dann vll. der unbenutzte Speicher auf die Festplatte ausgelagert wird, und das beim Freigeben lange dauert?

mjenke 11. Aug 2010 12:31

AW: Freigabe von Objekten zeitaufwändig?
 
@jfheins:

Dieses Freigeben passiert während der Laufzeit immer mal wieder. Es gibt Grenzen, an denen ich neue Bearbeitungsschritte einleite und dabei erstmal alles aufräume, was ich nicht mehr brauche. Übrigens handelt es sich nicht um Speicherlecks, denn die habe ich in tagelanger Kleinarbeit gemeinsam mit einem Kollegen aufgestöbert und eliminiert. Alle Objekte, die erzeugt werden, werden auch wieder freigegeben. Ansonsten würde die Anwendung es gar nicht mehr schaffen, bis zum Ende durchzuarbeiten - hatten wir leider alles schon :-D

jfheins 11. Aug 2010 13:49

AW: Freigabe von Objekten zeitaufwändig?
 
Okay, dann sit die Quick n Dirty Lösung natürlich nicht optimal...

hast du schonmal daran gedacht, einen Profiler mitlaufen zu lassen?

franktron 11. Aug 2010 14:06

AW: Freigabe von Objekten zeitaufwändig?
 
Zitat:

Zitat von mjenke (Beitrag 1040527)
Dennoch baut die Anwendung diese ganzen Objekte innerhalb weniger Minuten auf (3-4 Minuten)

Ich frage mich hier was du da treibst 3-4 Min Objecte zu erstellen wie viele sind das den.
Oder hast du noch eine Pentium 1 ?

mjenke 31. Aug 2010 08:29

AW: Freigabe von Objekten zeitaufwändig?
 
Um noch eine letzte Rückmeldung zu geben - für den Fall, dass es noch einen interessiert - inzwischen ist auch die letzte Bremse beseitigt.

Kurzer Hintergrund: Die Anwendung plant an Hand von BoundingBoxen die Verteilung von Anzeigen innerhalb eines Katalogs. Dabei stehen verschiedene Anzeigen in einer Beziehung zueinander und müssen nach bestimmten Regeln auf gleichen, vorhergehenden oder nachfolgenden Doppelseiten platziert werden. Die Daten kommen als XML an, werden verarbeitet und es wird XML wieder weggeschrieben.

Um verschiedenste Umbruchvarianten durchzuprobieren, werden baumartig verschiedene Umbruchzweige geöffnet und die Anzeigen (da sie innerhalb jeder Umbruchvariante angepackt und mit Zusatzdaten versehen werden) geklont. Um es kurz zu machen: Die Anwendung klont wie wahnsinnig und erzeugt viele, viele, viele, viele Objekte.

Innerhalb des Klonens einer Anzeige gab es ein letztes Problem:
  • Zu einer Anzeige gibt es Schnittkanten. Diese Schnittkanten geben vor, wo eine Anzeige zerteilt werden darf, um in mehreren Blöcken auf der Seite zu erscheinen
  • Die Schnittkanten werden bei der Erzeugung des Objektes durch Analyse des übergebenen XML erzeugt

Also etwa:
Code:
TUmbrObjekt.Create ( XML: IXMLDOMNode );
begin
  [...]
  AnalyzeXml ( XML );     // Analyse des uebergebenen XML
  [...]
end;
Die Methode AnalyzeXML ist dann dafür zuständig, dass die entsprechenden Unterobjekte, welche die einzelnen Schnittkanten repräsentieren, erzeugt werden.

Grob gesagt (handelt sich hier um eine extreme Vereinfachung) habe ich also ein Objekt folgenden Aufbaus:
Code:
TUmbrObjekt = class
  [...]
  private
    FXML: IXMLDOMNode;  // Hier wird das XML der Initialisierung vorgehalten
    FSchnittkanten: Array Of TSchnittkante;
  [...]
end;
Das Objekt kann sich selbst aber auch klonen. Und dabei bin ich folgendermaßen vorgegangen:
Code:
function TUmbrObjekt.Clone: TUmbrObjekt;
var
  i: Integer;
begin
  Result := TUmbrObjekt.Create ( FXML );
  for i := 0 to High ( FSchnittkanten ) do begin
    // self.FSchnittkanten[i] an Result anhängen
  end;
end;
Und genau darin lag der Fehler: Sowohl im Create werden Schnittkanten durch das XML erzeugt, als auch während des Klon-Vorgangs zusätzlich noch einmal an den Klon angehängt. Auf diese Weise habe ich die Anzahl der Unterobjekte explosionsartig vermehrt.

Nachdem ich das aufgeräumt hatte, konnte ich die Bearbeitungszeit dramatisch verkürzen. Aus den ursprünglichen knapp 80 Minuten wurden bei gleichen Daten 1,5 Minuten. Mit dem Gesamtdatenbestand, der letzten Endes einen Katalog von etwa 800 Seiten erzeugt, schrumpfte die Bearbeitungszeit von über 4 Stunden auf 5 Minuten.

Vielen Dank für die Hilfe!!!!

:-D

pertzschc 31. Aug 2010 09:07

AW: Freigabe von Objekten zeitaufwändig?
 
Zitat:

Zitat von mjenke (Beitrag 1046239)
Kurzer Hintergrund: Die Anwendung plant an Hand von BoundingBoxen die Verteilung von Anzeigen innerhalb eines Katalogs...

Hallo Matthias,

genau eine solche Erklärung hättest Du sinnvollerweise an den Anfang Deines Posts gestellt, dann hätte Dir besser und gezielter geholfen werden können.

Gruß,
Christoph


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:53 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz