Re: Wo gebt ihr Objekte frei?
^^^^
|
Re: Wo gebt ihr Objekte frei?
Rofl, FreeAndNil hat seinen Sinn, mach bitte einen neuen Thread dazu auf und ich bin bereit das zu beantworten bzw. guck mal in der DP, ich glaub das Thema hatten wir schon.
|
Re: Wo gebt ihr Objekte frei?
Hi,
@Popov: Ich gebe Dir Recht, in einer procedure(für lokale Variablen) kann man auf FreeAndNil verzichten und "besser" Objekt.free aufrufen. Deshalb stand das in meinem Bsp. auch als Kommentar dahinter. Bei mir wird allerdings durchgehend FreeAndNil verwendet, über den "Sinn und Unsinn" lässt sich sicher streiten. Aber Fakt ist: Wenn man "Multi-Threaded" arbeitet ist es schon ne feine Sache mit FreeAndNil zu Arbeiten, und vor dem Zugriff auf die Variable mit Assigned(xyz) zu prüfen, ob es noch existiert. Zwar hast Du Recht das es "meistens" überflüssig(90%) ist, allerdings stürzt Dein Programm ab wenn die 10% eintreten, meine nicht ;-) Greetz DataCool |
Re: Wo gebt ihr Objekte frei?
Moin Popov,
falls Du inzwischen Deinen Kaffee hattest kannst Du ja weiterlesen, ansonsten heb's Dir für nach dem Kaffee auf ;-) In DataCools Beispiel wurde TargetBMP als Wertparameter übergeben, dem man also in der Methode einen Wert zuweisen kann, ohne dass es an den Aufrufer durchschlägt. Wenn dieses Objekt dann auch nicht in der Prozedure wieder freigegeben wird, hat man ein Speicherleck, ausserdem bekommt der Aufrufer nicht, was er haben wollte. Nimmt man einen const Parameter kommt man damit nicht durch, da einem der Compiler auf die Finger haut. Freigeben kann ich das damit übergebene Objekt ja immer. Egal ob es nun ein var- out- const- oder WertParameter ist. |
Re: Wo gebt ihr Objekte frei?
Zitat:
Delphi-Quellcode:
So ist beim Methodenaufruf sofort ersichtlich, dass ein Objekt erzeugt wird.
Create...
Für komplett eigene Klassen benutze ich Referenzzählung zur Speicherverwaltung. Ich habe eine Klasse TCountedObject, die TObject um eine Zählervariable erweitert. TCountedObject besitzt die Methoden Retain, die den Referenzzähler um 1 erhöht und Release, die den Zähler um 1 dekrementiert und Free aufruft, wenn der Zähler 0 erreicht. Ausserdem gibt es noch die Methode AutoRelease, die das Objekt für einen späteren Aufruf von Release vormerkt. Dafür gibt es noch die Singleton-Klasse TAutoReleasePool, die eine Liste von TCountedObjects verwaltet. Der Aufruf von AutoRelease fügt das Objekt dieser Liste hinzu. Im OnIdle-Event von Application wird dann Release für alle Objekte im AutoReleasePool aufgerufen. So kann eine Methode ein TCountedObject erzeugen, sofort AutoRelease dafür aufrufen und das Objekt dann an den Aufrufer zurückgeben. Will der Aufrufer das Objekt nicht über die aktuelle Methode hinaus verwenden, braucht er gar nichts zu tun - sobald die aktuelle Ereignisverarbeitung abgeschlossen ist, wird im Idle-Event der Anwendung für das Objekt Release aufgerufen, was den Referenzzähler auf 0 dekrementiert und das Objekt damit freigibt. Will der Aufrufer das Objekt länger behalten, ruft er Retain auf. Damit überlebt das Objekt den Release-Aufruf im OnIdle. Weil der Aufrufer Retain aufgerufen hat, ist er dann auch für die Freigabe mit Release verantwortlich. Dieser Mechanismus wirkt erstmal recht kompliziert, aber er sorgt dafür, das man normalerweise eine korrekte Speicherverwaltung durch Befolgen von wenigen einfachen Regeln erhält: 1. Ein Objekt, das ein anderes Objekt erzeugt (durch direkten Aufruf des Konstruktors oder durch eine Funktion namens CreateXYZ), ist dafür verantwortlich, durch Aufruf von Release für die Freigabe zu sorgen 2. Ein Objekt, das eine Referenz auf anderes Objekt dauerhaft speichert (also in einer nicht lokalen Variablen), muss für dieses Objekt Retain aufrufen. Danach ist es auch für den Aufruf von Release verantwortlich, als hätte es das Objekt selbst erzeugt. 3. Eine Funktion, die ein Objekt erzeugt und an den Aufrufer zurückgibt, ohne eine Referenz auf das Objekt zu behalten, kann statt Release AutoRelease aufrufen und kommt damit ihrer Verpflichtung, Release aufzurufen, nach und kann das Objekt trotzdem noch zurückgeben. Problematisch sind dann nur noch Strukturen, bei denen Objekte gegenseitige Referenzen speichern. Hier würde dieses Verfahren zu einem Speicherleck führen, wenn sich die beiden Objekte gegenseitig Retainen. Normalerweise ist es dann sinnvoll, eine Hierarchie zu definieren, in der eins der Objekte dem anderen übergeordnet ist. Das übergeordnete Objekt ruft dann Retain und Release für das untergeordnete auf, aber nicht umgekehrt. Um Objekte mit Referenzzählung von solchen ohne Referenzzählung (die gesamte Delphi-Standardbibliothek) zu unterscheiden, verwende ich für von TCountedObject abgleitete Klassen immer das Namenspräfix TC. Stefan |
Re: Wo gebt ihr Objekte frei?
Zitat:
Zitat:
Und nein, mir ist noch kein einziges Mal mein Programm um die Ohren geflogen weil ich auf ein Objekt zugegriffen habe das nicht da ist. Und ja, auch ich arbeite gelegentlich mit der Information Nil, aber dann wird Nil bewußt gesetzt. FreeAndNil ist als ob man mit Variant Variablen arbeiten würde. Dann kann man die Variable als String nutzen und kann sogar damit rechnen wenn zufällig nur Zahlen drin vorkommen. Eigentlich kann man dann sofort zu VB wechseln. EDIT: Zitat:
|
Re: Wo gebt ihr Objekte frei?
Ich werde immer lieber einfach Free aufrufen für interne Objekte in den Destruktoren anstatt mir die Finger weiter zu demolieren, nur damit ich dann statt dessen
Delphi-Quellcode:
schreiben muss für eine sichere Freigabe.
if assigned(AObj) then
AObj.Destroy; Schon allein "bewußt mit Nil arbeiten" setzt voraus, dass du behaupten würdest, dass deine Objekte niemals durch einen Fehler NIL sind. Schon allein ein EOutOfResource Exception z.B. im Konstruktor eines Bitmaps würde dir ein NIL Objekt bescheren - mit dem du aber niemals rechnest, da das Anlegen von Bitmaps immer klappt. Wenn nun mal weiter annehmen, dass die Methoden welches das Bitmap nutzen entsprechend die Instanz abprüfen und nichts passiert und dann im Destruktor direkt steht "Bitmap.Destroy", dann knallt es am Ende (schön sichtbar für den Kunden). Ich bin mir soweit auch sicher, dass Bitmaps eigentlich immer eine Instanz liefern, aber trotzdem rufe ich nicht direkt Destroy auf und bin damit nochmal ein wenig sicherer (trotz meiner fahrlässigen Annahme). Ansonsten gilt grundsätzlich jbg's Beitrag. Man kann meistens gar nicht so doof denken, wie auch z.T. die WinAPI einem in die Suppe spucken kann. Da kann man noch so sicher sein, im Fehlerfall bricht dann aber entsprechend alles zusammen sondern nur ein Teil. Zitat:
@Stefan.Buchholtz: Respekt! Ich würde niemals einen solchen Aufwand treiben zu wollen, nur um mir einen Garbagecollector zu bauen, der dann nur auf die von mir selbst geschriebenen Dinge wirken kann. Die eine Hälfte bequem, die andere Hälfte der Objekte Old-School. Aber wie gesagt: ich habe Respekt vor der Arbeit. Mich würde nur die Nutzung nicht unbedingt überzeugen. Würde es grundsätzlich für alle Objekte gelten, dann würde es mich überzeugen und ich würde es nutzen. Siehe entsprechende Sprachen mit Garbage-Collector. Da ist es im Sprachumfang und gilt automatisch für alle genutzten Elemente. |
Re: Wo gebt ihr Objekte frei?
Zitat:
Aber ich spreche doch nicht von Free, das benutze ich doch selbst. Ich spreche die ganze Zeit von FreeAndNil. |
Re: Wo gebt ihr Objekte frei?
Zitat:
Der Implementierungsaufwand von dem Ding war nicht groß - insgesamt sind das vielleicht 200-300 Zeilen. Dazu kommen noch Container-Klassen (Listen, Hashes), die die Referenzzählung unterstützen, das sind vielleicht auch noch ein paar 100 Zeilen. Und wenn man sowas einmal gebaut hat, ist es getan - dann kann man es in allen möglichen Projekten benutzen. Das wird in hauptsächlich einem größeren Projekt (sicherlich mehrere 100.000 Zeilen Code) eingesetzt, in dem (mittlerweile) sehr stark objektorientiert gearbeitet wird - insbesondere wird die Datenbank fast vollständig durch ein Objektmodell abgebildet. Wir haben also sehr viele eigene Klassen, bei denen auch häufig Objekte von mehreren anderen Objekten parallel benutzt werden Dann braucht man ein System, um den Überblick nicht zu verlieren. Das ganze Konzept habe ich überigens komplett aus dem API von MacOS X übernommen. :mrgreen: Stefan |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:18 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