Ist das Überschreiben von Object.finalize () wirklich schlecht?

34

Die beiden Hauptargumente gegen das Überschreiben Object.finalize()sind:

  1. Sie können sich nicht entscheiden, wann es heißt.

  2. Es kann überhaupt nicht aufgerufen werden.

Wenn ich das richtig verstehe, denke ich nicht, dass das gute Gründe genug sind, um Object.finalize()so viel zu hassen .

  1. Es ist Sache der VM-Implementierung und des GC, zu bestimmen, wann der richtige Zeitpunkt für die Freigabe eines Objekts ist, nicht der Entwickler. Warum ist es wichtig zu entscheiden, wann Object.finalize()angerufen wird?

  2. Normalerweise, und korrigieren Sie mich, wenn ich falsch liege, wird das einzige Mal Object.finalize(), wenn die Anwendung beendet wird, bevor der GC die Möglichkeit hat, ausgeführt zu werden, nicht aufgerufen. Das Objekt wurde jedoch ohnehin freigegeben, als der Prozess der Anwendung damit beendet wurde. Also Object.finalize()wurde nicht angerufen, weil es nicht nötig war, angerufen zu werden. Warum sollte sich der Entwickler darum kümmern?

Jedes Mal, wenn ich Objekte verwende, die ich manuell schließen muss (z. B. Dateizugriffsnummern und Verbindungen), bin ich sehr frustriert. Ich muss ständig prüfen, ob ein Objekt eine Implementierung von hat close(), und ich bin mir sicher, dass ich in der Vergangenheit einige Aufrufe verpasst habe. Warum ist es nicht einfacher und sicherer, es der VM und dem GC zu überlassen, diese Objekte zu entsorgen, indem Sie die close()Implementierung einfügen Object.finalize()?

AxiomaticNexus
quelle
1
Beachten Sie auch: Wie bei vielen APIs aus der Java 1.0-Ära ist auch die Thread-Semantik finalize()ein bisschen durcheinander. Wenn Sie es jemals implementieren, stellen Sie sicher, dass es in Bezug auf alle anderen Methoden für dasselbe Objekt threadsicher ist.
billc.cn
2
Wenn Sie Leute sagen hören, dass Finalizer schlecht sind, heißt das nicht, dass Ihr Programm nicht mehr funktioniert, wenn Sie sie haben. sie bedeuten, dass die ganze Idee der Finalisierung ziemlich nutzlos ist.
user253751
1
+1 auf diese Frage. Die meisten der folgenden Antworten geben an, dass die Ressourcen wie Dateideskriptoren begrenzt sind und manuell erfasst werden sollten. Dasselbe galt für den Speicher. Wenn wir also eine Verzögerung bei der Speichererfassung akzeptieren, warum nicht für Dateideskriptoren und / oder andere Ressourcen?
mbonnin
Wenn Sie Ihren letzten Absatz ansprechen, können Sie es Java überlassen, das Schließen von Dingen wie Dateihandles und Verbindungen mit sehr geringem Aufwand zu erledigen. Verwenden Sie den Try-with-Resources-Block - er wurde bereits einige Male in Antworten und Kommentaren erwähnt, aber ich denke, es lohnt sich, ihn hier einzufügen. Das Oracle-Tutorial dazu finden Sie unter docs.oracle.com/javase/tutorial/essential/exceptions/…
Jeutnarg

Antworten:

45

Nach meiner Erfahrung gibt es nur einen Grund für das Überschreiben Object.finalize(), aber es ist ein sehr guter Grund :

Um Fehlerprotokollierungscode zu platzieren, finalize()der Sie benachrichtigt, wenn Sie das Aufrufen vergessen close().

Die statische Analyse kann nur Auslassungen in Szenarien mit geringer Auslastung erkennen, und die Compiler-Warnungen, die in einer anderen Antwort erwähnt werden, enthalten eine so vereinfachte Sicht der Dinge, dass Sie sie tatsächlich deaktivieren müssen, um alles zu tun, was nicht trivial ist. (Ich habe weit mehr Warnungen aktiviert als jeder andere Programmierer, den ich kenne oder von dem ich je gehört habe, aber ich habe keine dummen Warnungen aktiviert.)

Die Finalisierung scheint ein guter Mechanismus zu sein, um sicherzustellen, dass die Ressourcen nicht ungenutzt bleiben. Die meisten Menschen sehen dies jedoch völlig falsch: Sie sehen darin einen alternativen Fallback-Mechanismus, eine "zweite Chance", die die Ressourcen automatisch schützt Tag durch Entsorgung der Ressourcen, die sie vergessen haben. Das ist absolut falsch . Es muss nur eine Möglichkeit geben, etwas zu tun: Entweder schließen Sie immer alles, oder die Finalisierung schließt immer alles. Da die Finalisierung jedoch unzuverlässig ist, kann es nicht die Finalisierung sein.

Es gibt also dieses Schema, das ich Mandatory Disposal nenne , und das besagt, dass der Programmierer dafür verantwortlich ist, immer explizit alles zu schließen, wasCloseable oder implementiert AutoCloseable. (Die Anweisung "try-with-resources" gilt immer noch als explizites Schließen.) Natürlich kann der Programmierer dies vergessen. Hier kommt also die Finalisierung ins Spiel, aber nicht als magische Fee, die die Dinge am Ende auf magische Weise richtig macht: Wenn die Finalisierung entdeckt wird das close()wurde nicht aufgerufen, tut es nichtversuchen, es aufzurufen, gerade weil es (mit mathematischer Sicherheit) Horden von n00b-Programmierern geben wird, die sich darauf verlassen werden, dass es die Arbeit erledigt, für die sie zu faul oder zu abwesend waren. Wenn Finalization bei der obligatorischen Entsorgung feststellt, dass diese Funktion close()nicht aufgerufen wurde, wird eine leuchtend rote Fehlermeldung protokolliert, die dem Programmierer mit großen, fetten Großbuchstaben mitteilt, er solle sein Problem beheben.

Als zusätzlichen Vorteil geht das Gerücht aus, dass "die JVM eine triviale finalize () -Methode ignorieren wird (z. B. eine, die nur zurückkehrt, ohne etwas zu tun, wie es in der Object-Klasse definiert ist)", sodass Sie bei obligatorischer Entsorgung jegliche Finalisierung vermeiden können Overhead in Ihrem gesamten System ( Informationen darüber, wie schrecklich dieser Overhead ist, finden Sie in der Antwort von alip ), indem Sie Ihre finalize()Methode wie folgt codieren :

@Override
protected void finalize() throws Throwable
{
    if( Global.DEBUG && !closed )
    {
        Log.Error( "FORGOT TO CLOSE THIS!" );
    }
    //super.finalize(); see alip's comment on why this should not be invoked.
}

Die Idee dahinter ist, dass Global.DEBUGes sich um eine static finalVariable handelt, deren Wert zum Kompilierungszeitpunkt bekannt ist. Wenn dies falseder Fall ist, gibt der Compiler überhaupt keinen Code für die gesamte ifAnweisung aus, wodurch dies zu einem trivialen (leeren) Finalizer wird, der wiederum bedeutet, dass Ihre Klasse so behandelt wird, als hätte sie keinen Finalizer. (In C # würde dies mit einem netten #if DEBUGBlock geschehen , aber was können wir tun, das ist Java, wo wir anscheinend Einfachheit im Code mit zusätzlichem Overhead im Gehirn bezahlen.)

Weitere Informationen zur Entsorgungspflicht mit zusätzlichen Erläuterungen zur Entsorgung von Ressourcen in dot Net finden Sie hier: michael.gr: Entsorgungspflicht vs.

Mike Nakis
quelle
2
@MikeNakis Vergessen Sie nicht, dass Closeable beim zweiten Aufruf nichts tut: docs.oracle.com/javase/7/docs/api/java/io/Closeable.html . Ich gebe zu, dass ich manchmal eine Warnung protokolliert habe, wenn meine Klassen zweimal geschlossen sind, aber technisch sollte man das nicht einmal tun. Technisch gesehen ist das mehrmalige Aufrufen von .close () bei Closable durchaus gültig.
Patrick M
1
@usr es läuft alles darauf hinaus, ob Sie Ihren Tests vertrauen oder ob Sie Ihren Tests nicht vertrauen. Wenn Sie Ihren Tests nicht vertrauen, gehen Sie sicher voran und erleiden den Finalisierungsaufwand ebenfalls close() für alle Fälle. Ich glaube, wenn meine Tests nicht vertrauenswürdig sind, sollte ich das System besser nicht für die Produktion freigeben.
Mike Nakis
3
Damit das if( Global.DEBUG && ...Konstrukt funktioniert und die JVM die finalize()Methode als trivial ignoriert , Global.DEBUGmuss @Mike zum Zeitpunkt der Kompilierung festgelegt werden (im Gegensatz zu injiziertem Code usw.). Der Aufruf super.finalize()außerhalb des if-Blocks ist auch für die JVM ausreichend, um ihn als nicht trivial zu behandeln (unabhängig vom Wert von Global.DEBUG, zumindest in HotSpot 1.8), selbst wenn auch der Aufruf der Superklasse #finalize()trivial ist!
Alip
1
@ Mike Ich fürchte, das ist der Fall. Ich habe es mit (einer leicht modifizierten Version) des Tests in dem Artikel getestet, den Sie verlinkt haben , und eine ausführliche GC-Ausgabe (zusammen mit einer überraschend schlechten Leistung) bestätigt, dass die Objekte in den Survivor- / Old-Generation-Space kopiert wurden und einen vollständigen Heap-GC benötigen, um sie zu erhalten loswerden.
Alip
1
Was oft übersehen wird, ist das Risiko einer unerwartet frühen Sammlung von Objekten, was die Freigabe von Ressourcen im Finalizer zu einer sehr gefährlichen Aktion macht. Vor Java 9 besteht die einzige Möglichkeit, um sicherzustellen, dass ein Finalizer die Ressource nicht schließt, während sie noch verwendet wird, darin, das Objekt sowohl im Finalizer als auch in den Methoden, die die Ressource verwenden, zu synchronisieren. Deshalb funktioniert es in java.io. Wenn diese Art von Thread-Sicherheit nicht auf der Wunschliste stand, wird der durch finalize()
Holger,
28

Jedes Mal, wenn ich Objekte verwende, die ich manuell schließen muss (z. B. Dateizugriffsnummern und Verbindungen), bin ich sehr frustriert. [...] Warum ist es nicht einfacher und sicherer, es einfach der VM und dem GC zu überlassen, diese Objekte durch Einfügen der close()Implementierung zu entsorgen Object.finalize()?

Da Datei-Handles und -Verbindungen (d. H. Dateideskriptoren auf Linux- und POSIX-Systemen) eine recht knappe Ressource sind (auf einigen Systemen sind sie möglicherweise auf 256 oder auf anderen auf 16384 beschränkt; siehe setrlimit (2) ). Es gibt keine Garantie dafür, dass der GC häufig genug (oder zum richtigen Zeitpunkt) angerufen wird, um die Erschöpfung derart begrenzter Ressourcen zu vermeiden. Und wenn der GC nicht genügend aufgerufen wird (oder die Finalisierung nicht zum richtigen Zeitpunkt ausgeführt wird), erreichen Sie dieses (möglicherweise niedrige) Limit.

Finalisierung ist in der JVM eine "Best-Effort-Sache". Es kann sein, dass es nicht oder nur sehr spät aufgerufen wird ... Insbesondere, wenn Sie viel RAM haben oder wenn Ihr Programm nicht viele Objekte zuweist (oder wenn die meisten von ihnen sterben, bevor sie an einige weitergeleitet werden, die alt genug sind) Generierung durch ein Kopier-Generierungs-GC), kann der GC sehr selten aufgerufen werden, und die Finalisierungen werden möglicherweise nicht sehr oft (oder gar nicht) ausgeführt.

Also closeDateideskriptoren möglichst explizit. Wenn Sie Angst haben, diese zu verlieren, verwenden Sie die Finalisierung als zusätzliche Maßnahme, nicht als Hauptmaßnahme.

Basile Starynkevitch
quelle
7
Ich würde hinzufügen, dass das Schließen eines Streams zu einer Datei oder einem Socket diese normalerweise löscht. Das unnötige Öffnen von Streams erhöht das Risiko eines Datenverlusts, wenn der Strom
2
Obwohl die Anzahl der zulässigen Filedeskriptoren gering sein mag, ist dies nicht der eigentliche Knackpunkt, da man dies zumindest als Signal für den GC verwenden könnte. Das wirklich problematische ist, dass es a) für den GC völlig undurchsichtig ist, wie viel nicht durch den GC verwaltete Ressourcen daran hängen, und b) viele dieser Ressourcen eindeutig sind, sodass andere möglicherweise blockiert oder verweigert werden.
Deduplizierer
2
Wenn Sie eine Datei geöffnet lassen, kann dies zu Beeinträchtigungen für andere Benutzer führen. (Windows 8 XPS-Viewer, ich freue mich auf Sie!)
Loren Pechtel
2
"Wenn Sie Angst haben [Dateideskriptoren] zu verlieren, verwenden Sie die Finalisierung als zusätzliche Maßnahme, nicht als die Hauptmaßnahme." Diese Aussage klingt für mich faul. Wenn Sie Ihren Code gut entwerfen, sollten Sie dann wirklich redundanten Code einführen, der die Bereinigung auf mehrere Stellen verteilt?
Mucaho
2
@BasileStarynkevitch Sie meinen, dass in einer idealen Welt Redundanz zwar schlecht ist, aber in der Praxis, in der Sie nicht alle relevanten Aspekte vorhersehen können, besser auf Nummer sicher gehen als auf Nummer sicher gehen?
Mucaho
13

Betrachten Sie die Sache so: Sie sollten nur Code schreiben, der (a) korrekt ist (ansonsten ist Ihr Programm einfach falsch) und (b) notwendig (ansonsten ist Ihr Code zu groß, was bedeutet, dass mehr RAM erforderlich ist, mehr Zyklen aufgewendet werden nutzlose Dinge, mehr Mühe, es zu verstehen, mehr Zeit für die Pflege usw. usw.)

Überlegen Sie nun, was Sie in einem Finalizer tun möchten. Entweder ist es notwendig. In diesem Fall können Sie es nicht in einen Finalizer einfügen, da Sie nicht wissen, ob es aufgerufen wird. Das ist nicht gut genug. Oder es ist nicht nötig - dann solltest du es gar nicht erst schreiben! In jedem Fall ist es die falsche Wahl, es in den Finalizer zu setzen.

(Beachten Sie, dass die Beispiele , die Sie nennen, wie Datei - Streams zu schließen, sehen , als ob sie sind nicht wirklich notwendig, aber sie sind. Es ist nur so , bis Sie die Grenze für offene Datei - Handles auf Ihrem System treffen, werden Sie nicht Mitteilung , dass Ihr Code ist falsch. Aber diese Grenze ist eine Funktion des Betriebssystems und ist daher noch unberechenbarer als die Politik der JVM für Finalizers, so ist es wirklich, wirklich ist wichtig , dass Sie nicht verschwenden Datei - Handles.)

Kilian Foth
quelle
Wenn ich nur Code schreiben soll, der "notwendig" ist, sollte ich dann das gesamte Styling in allen meinen GUI-Anwendungen vermeiden? Sicherlich ist nichts davon notwendig; Die GUIs funktionieren ohne Styling einwandfrei, sie sehen schrecklich aus. Über den Finalizer kann es notwendig sein, etwas zu tun, aber es ist immer noch in Ordnung, es in einen Finalizer zu setzen, da der Finalizer, wenn überhaupt, während der Objekt-GC aufgerufen wird. Wenn Sie eine Ressource schließen müssen, insbesondere wenn sie für die Garbage Collection bereit ist, ist ein Finalizer optimal. Entweder beendet das Programm die Freigabe Ihrer Ressource oder der Finalizer wird aufgerufen.
Kröw
Wenn ich ein RAM-schweres, teuer zu erstellendes, schließbares Objekt habe und beschließe, es schwach zu referenzieren, damit es gelöscht werden kann, wenn es nicht benötigt wird, könnte ich es finalize()zum Schließen verwenden, falls ein GC-Zyklus wirklich frei werden muss RAM. Ansonsten würde ich das Objekt im RAM behalten, anstatt es jedes Mal neu generieren und schließen zu müssen, wenn ich es verwenden muss. Sicher, die Ressourcen, die geöffnet werden, werden erst freigegeben, wenn das Objekt in einem bestimmten Zeitraum gecodet wurde. Es kann jedoch sein, dass ich nicht garantieren muss, dass meine Ressourcen zu einem bestimmten Zeitpunkt freigegeben werden.
Kröw
8

Einer der Hauptgründe, sich nicht auf Finalizer zu verlassen, ist, dass die meisten Ressourcen, die man im Finalizer aufräumen könnte, sehr begrenzt sind. Der Garbage Collector wird nur von Zeit zu Zeit ausgeführt, da das Durchsuchen von Referenzen, um festzustellen, ob etwas freigegeben werden kann, teuer ist. Dies bedeutet, dass es eine Weile dauern kann, bis Ihre Objekte tatsächlich zerstört werden. Wenn Sie beispielsweise viele Objekte haben, die kurzlebige Datenbankverbindungen öffnen, kann der Verbindungspool erschöpft sein, wenn die Finalizer diese Verbindungen bereinigen, während der Garbage Collector darauf wartet, dass er endlich ausgeführt wird und die fertigen Verbindungen freigibt. Aufgrund des Wartens kommt es dann zu einem großen Rückstand an Anfragen in der Warteschlange, die den Verbindungspool schnell wieder erschöpfen. Es'

Durch die Verwendung von "try-with-resources" ist es außerdem einfach, "schließbare" Objekte nach Abschluss zu schließen. Wenn Sie mit diesem Konstrukt nicht vertraut sind, empfehlen wir Ihnen, es sich anzusehen : https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Hunde
quelle
8

Abgesehen davon, warum es im Allgemeinen eine schlechte Idee ist, es dem Finalizer zu überlassen, Ressourcen freizugeben, sind finalisierbare Objekte mit Performance-Overhead verbunden.

Aus Java Theorie und Praxis: Garbage Collection und Performance (Brian Goetz), Finalizer sind nicht dein Freund :

Objekte mit Finalisierern (solche mit einer nicht-trivialen finalize () -Methode) haben im Vergleich zu Objekten ohne Finalisierern einen erheblichen Overhead und sollten sparsam verwendet werden. Finalisierbare Objekte sind sowohl langsamer zuzuweisen als auch langsamer zu sammeln. Zum Zeitpunkt der Zuweisung muss die JVM finalisierbare Objekte beim Garbage Collector registrieren, und finalisierbare Objekte müssen (zumindest in der HotSpot-JVM-Implementierung) einem langsameren Zuweisungspfad folgen als die meisten anderen Objekte. Ebenso ist das Sammeln finalisierbarer Objekte langsamer. Es dauert mindestens zwei Speicherbereinigungszyklen (im besten Fall), bis ein finalisierbares Objekt wiederhergestellt werden kann, und der Garbage Collector muss zusätzliche Arbeit leisten, um den Finalizer aufzurufen. Das Ergebnis ist mehr Zeit für das Zuweisen und Sammeln von Objekten und mehr Druck auf den Müllsammler. weil der von nicht erreichbaren finalisierbaren Objekten verwendete Speicher länger erhalten bleibt. Kombinieren Sie dies mit der Tatsache, dass Finalizer garantiert nicht in einem vorhersehbaren Zeitrahmen oder überhaupt nicht ausgeführt werden und Sie sehen, dass es relativ wenige Situationen gibt, in denen Finalization das richtige Werkzeug ist.

alip
quelle
Hervorragender Punkt. Siehe meine Antwort, die ein Mittel zur Vermeidung des Leistungsaufwands von bietet finalize().
Mike Nakis
7

Mein (am wenigsten) bevorzugter Grund für das Vermeiden Object.finalizeist nicht, dass Objekte möglicherweise abgeschlossen werden, nachdem Sie es erwartet haben, sondern dass sie abgeschlossen werden können, bevor Sie es erwartet haben. Das Problem besteht nicht darin, dass ein Objekt, das sich noch im Gültigkeitsbereich befindet, vor dem Verlassen des Gültigkeitsbereichs finalisiert werden kann, wenn Java feststellt, dass es nicht mehr erreichbar ist.

void test() {
   HasFinalize myObject = ...;
   OutputStream os = myObject.stream;

   // myObject is no-longer reachable at this point, 
   // even though it is in scope. But objects are finalized
   // based on reachability.
   // And since finalization is on another thread, it 
   // could happen before or in the middle of the write .. 
   // closing the stream and causing much fun.
   os.write("Hello World");
}

Siehe diese Frage für weitere Details. Noch lustiger ist, dass diese Entscheidung möglicherweise erst nach dem Start der Hot-Spot-Optimierung getroffen wird, was das Debuggen schmerzhaft macht.

Michael Anderson
quelle
1
Die Sache ist, dass HasFinalize.streames sich um ein separat finalisierbares Objekt handeln sollte. Das heißt, die Finalisierung von HasFinalizesollte nicht finalisiert werden oder zu einer Bereinigung führen stream. Oder wenn es sollte, dann sollte es streamunzugänglich machen .
aktueller
4

Ich muss ständig überprüfen, ob ein Objekt eine Implementierung von close () hat, und ich bin sicher, dass ich in der Vergangenheit einige Aufrufe verpasst habe.

In Eclipse erhalte ich eine Warnung, wenn ich vergesse, etwas zu schließen, das Closeable/ implementiert AutoCloseable. Ich bin mir nicht sicher, ob es sich um eine Eclipse-Sache handelt oder ob sie Teil des offiziellen Compilers ist, aber Sie könnten versuchen, ähnliche statische Analyse-Tools zu verwenden, um Ihnen dabei zu helfen. Mit FindBugs können Sie möglicherweise überprüfen, ob Sie vergessen haben, eine Ressource zu schließen.

Nebu Pookins
quelle
1
Gute Idee zu erwähnen AutoCloseable. Es macht es denkbar einfach, Ressourcen mit Try-with-Resources zu verwalten. Dies macht einige der Argumente in der Frage ungültig.
2

Zu Ihrer ersten Frage:

Es ist Sache der VM-Implementierung und des GC, zu bestimmen, wann der richtige Zeitpunkt für die Freigabe eines Objekts ist, nicht der Entwickler. Warum ist es wichtig zu entscheiden, wann Object.finalize()angerufen wird?

Nun, die JVM bestimmt, wann es ein guter Punkt ist, den für ein Objekt zugewiesenen Speicher zurückzugewinnen. Dies ist nicht unbedingt der Zeitpunkt, an dem die Ressourcenbereinigung, die Sie durchführen möchten finalize(), stattfinden soll. Dies wird in der Frage „finalize () auf ein stark erreichbares Objekt in Java 8“ zu SO veranschaulicht . Dort wurde eine close()Methode von einer finalize()Methode aufgerufen , während der Versuch, von demselben Objekt aus dem Stream zu lesen, noch aussteht. Neben der bekannten Möglichkeit, dass ein finalize()Anruf zu spät eingeht, besteht die Möglichkeit, dass er zu früh eingeht.

Die Prämisse Ihrer zweiten Frage:

Normalerweise, und korrigieren Sie mich, wenn ich falsch liege, wird das einzige Mal Object.finalize(), wenn die Anwendung beendet wird, bevor der GC die Möglichkeit hat, ausgeführt zu werden, nicht aufgerufen.

ist einfach falsch. Es ist nicht erforderlich, dass eine JVM die Finalisierung unterstützt. Nun, es ist nicht völlig falsch, da Sie es immer noch als "die Anwendung wurde vor dem Abschluss beendet" interpretieren könnten, vorausgesetzt, dass Ihre Anwendung jemals beendet wird.

Beachten Sie jedoch den kleinen Unterschied zwischen "GC" Ihrer ursprünglichen Aussage und dem Begriff "Finalisierung". Die Garbage Collection unterscheidet sich von der Finalisierung. Sobald die Speicherverwaltung feststellt, dass ein Objekt nicht erreichbar ist, kann es einfach seinen Speicherplatz zurückfordern, wenn entweder keine spezielle finalize()Methode zur Verfügung steht oder die Finalisierung einfach nicht unterstützt wird oder das Objekt für die Finalisierung in eine Warteschlange gestellt wird. Somit impliziert der Abschluss eines Speicherbereinigungszyklus nicht, dass Finalisierer ausgeführt werden. Dies kann zu einem späteren Zeitpunkt geschehen, wenn die Warteschlange verarbeitet wird, oder überhaupt nicht.

Dieser Punkt ist auch der Grund, warum es selbst bei JVMs mit Finalisierungsunterstützung gefährlich ist, sich bei der Bereinigung von Ressourcen darauf zu verlassen. Die Speicherbereinigung ist Teil der Speicherverwaltung und wird daher durch den Speicherbedarf ausgelöst. Es ist möglich, dass die Garbage Collection niemals ausgeführt wird, weil während der gesamten Laufzeit genügend Speicherplatz vorhanden ist (was auch immer noch in die Beschreibung "Die Anwendung wurde beendet, bevor der GC die Möglichkeit zum Ausführen hatte" passt). Es ist auch möglich, dass der GC ausgeführt wird. Danach wird jedoch genügend Speicher freigegeben, sodass die Finalizer-Warteschlange nicht verarbeitet wird.

Mit anderen Worten, auf diese Weise verwaltete native Ressourcen sind der Speicherverwaltung immer noch fremd. Es ist zwar garantiert, dass ein OutOfMemoryErrorFehler erst ausgelöst wird, nachdem ausreichend versucht wurde, Speicher freizugeben, dies gilt jedoch nicht für native Ressourcen und die Finalisierung. Es ist möglich, dass das Öffnen einer Datei aufgrund unzureichender Ressourcen fehlschlägt, während die Finalisierungswarteschlange voll ist mit Objekten, die diese Ressourcen freigeben könnten, falls der Finalizer jemals ausgeführt wird.

Holger
quelle