Es scheint, als hätten die Leute die manuelle Speicherverwaltung satt, also haben sie die Müllabfuhr erfunden, und das Leben war einigermaßen gut. Aber was ist mit allen anderen Ressourcentypen? Dateideskriptoren, Sockets oder sogar vom Benutzer erstellte Daten wie Datenbankverbindungen?
Das fühlt sich wie eine naive Frage an, aber ich kann keinen Ort finden, an dem jemand sie gestellt hat. Betrachten wir Dateideskriptoren. Angenommen, ein Programm weiß, dass es beim Start nur 4000 fds zur Verfügung haben darf. Wann immer es eine Operation ausführt, die einen Dateideskriptor öffnet, was wäre, wenn dies der Fall wäre
- Stellen Sie sicher, dass es nicht zu Ende geht.
- Wenn dies der Fall ist, lösen Sie den Garbage Collector aus, wodurch eine Menge Speicher freigegeben wird.
- Wenn ein Teil des freigegebenen Speichers Verweise auf Dateideskriptoren enthält, schließen Sie diese sofort. Es weiß, dass der Speicher zu einer Ressource gehört, da der mit dieser Ressource verknüpfte Speicher beim ersten Öffnen mangels eines besseren Begriffs in einer 'Dateideskriptor-Registrierung' registriert wurde.
- Öffnen Sie einen neuen Dateideskriptor, kopieren Sie ihn in einen neuen Speicher, registrieren Sie diesen Speicherort in der 'Dateideskriptor-Registrierung' und geben Sie ihn an den Benutzer zurück.
Die Ressource würde also nicht sofort freigegeben, sondern immer dann freigegeben, wenn der gc ausgeführt wurde, was zumindest kurz vor dem Auslaufen der Ressource umfasst, vorausgesetzt, sie wird nicht vollständig genutzt.
Und es scheint, dass dies für viele benutzerdefinierte Probleme bei der Bereinigung von Ressourcen ausreichen würde. Es ist mir gelungen, hier einen einzigen Kommentar zu finden, der darauf verweist, dass eine ähnliche Bereinigung in C ++ mit einem Thread durchgeführt wird, der einen Verweis auf eine Ressource enthält, und ihn bereinigt, wenn nur noch ein einziger Verweis übrig ist (aus dem Bereinigungsthread), aber ich kann ' Es gibt keine Beweise dafür, dass es sich um eine Bibliothek oder einen Teil einer vorhandenen Sprache handelt.
quelle
Es gibt viele Programmiertechniken, um diese Art von Ressourcen zu verwalten.
C ++ - Programmierer verwenden häufig ein Muster namens Resource Acquisition is Initialization , kurz RAII. Dieses Muster stellt sicher, dass ein Objekt, an dem Ressourcen festgehalten werden, geschlossen wird, wenn es den Gültigkeitsbereich verlässt. Dies ist hilfreich, wenn die Lebensdauer des Objekts einem bestimmten Bereich im Programm entspricht (z. B. wenn es mit der Zeit übereinstimmt, zu der ein bestimmter Stapelrahmen auf dem Stapel vorhanden ist). Daher ist es hilfreich für Objekte, auf die lokale Variablen zeigen (Zeiger) auf dem Stapel gespeicherte Variablen), aber nicht so hilfreich für Objekte, auf die Zeiger zeigen, die auf dem Heap gespeichert sind.
Java, C # und viele andere Sprachen bieten eine Möglichkeit, eine Methode anzugeben, die aufgerufen wird, wenn ein Objekt nicht mehr aktiv ist und vom Garbage Collector erfasst werden soll. Siehe z. B. Finalizer
dispose()
und andere. Die Idee ist, dass der Programmierer eine solche Methode implementieren kann, so dass die Ressource explizit geschlossen wird, bevor das Objekt vom Garbage Collector freigegeben wird. Diese Ansätze weisen jedoch einige Probleme auf, über die Sie an anderer Stelle lesen können. Beispielsweise sammelt der Garbage Collector das Objekt möglicherweise erst viel später als gewünscht.C # und andere Sprachen bieten ein
using
Schlüsselwort, mit dem sichergestellt wird, dass Ressourcen geschlossen werden, nachdem sie nicht mehr benötigt werden (Sie vergessen also nicht, den Dateideskriptor oder eine andere Ressource zu schließen). Dies ist oft besser, als sich auf den Garbage Collector zu verlassen, um festzustellen, dass das Objekt nicht mehr aktiv ist. Siehe z . B. /programming//q/75401/781723 . Der allgemeine Begriff hier ist eine verwaltete Ressource . Diese Vorstellung baut auf RAII und Finalisierern auf und verbessert sie in gewisser Weise.quelle
Alle Speicher sind gleich, wenn ich nach 1K frage, ist es mir egal, woher im Adressraum die 1K kommt.
Wenn ich nach einem Dateihandle frage, möchte ich ein Handle für die Datei, die ich öffnen möchte. Wenn ein Dateihandle für eine Datei geöffnet ist, wird häufig der Zugriff anderer Prozesse oder Computer auf die Datei blockiert.
Daher müssen Dateihandles geschlossen werden, sobald sie nicht benötigt werden. Andernfalls blockieren sie andere Zugriffe auf die Datei, aber der Speicher muss nur zurückgefordert werden, wenn Ihnen die Datei ausgeht.
Das Ausführen eines GC-Durchlaufs ist kostspielig und wird nur „bei Bedarf“ durchgeführt. Es ist nicht möglich vorherzusagen, wann ein anderer Prozess ein Dateihandle benötigt, das Ihr Prozess möglicherweise nicht mehr verwendet, aber noch geöffnet hat.
quelle
Ich würde vermuten, dass der Grund, warum dies für andere Ressourcen nicht viel angegangen wurde, genau darin liegt, dass die meisten anderen Ressourcen bevorzugt so schnell wie möglich freigegeben werden, damit jeder sie wiederverwenden kann.
Beachten Sie natürlich, dass Ihr Beispiel jetzt unter Verwendung von "schwachen" Dateideskriptoren mit vorhandenen GC-Techniken bereitgestellt werden kann.
quelle
Es ist ziemlich einfach zu überprüfen, ob der Speicher nicht mehr verfügbar ist (und somit garantiert nicht mehr verwendet wird). Die meisten anderen Arten von Ressourcen können mit mehr oder weniger denselben Techniken verarbeitet werden (dh Ressourcenerfassung ist Initialisierung, RAII und das Gegenstück zur Freigabe, wenn der Benutzer zerstört wird, was ihn mit der Speicherverwaltung verbindet). Eine Art "Just-in-Time" -Freigabe ist im Allgemeinen nicht möglich (überprüfen Sie das Stoppproblem, Sie müssten herausfinden, dass zum letzten Mal eine Ressource verwendet wurde). Ja, manchmal kann es automatisch gemacht werden, aber es ist ein viel chaotischerer Fall als Speicher. Daher ist es größtenteils auf Benutzereingriffe angewiesen.
quelle