Die eigentliche Antwort lautet, dass der einzige Weg, um einen sicheren und effizienten Mechanismus für die Garbage Collection zu schaffen, die Unterstützung von undurchsichtigen Referenzen auf Sprachebene ist . (Oder umgekehrt, mangelnde Sprachunterstützung für direkte Speichermanipulation.)
Java und C # können dies, weil sie spezielle Referenztypen haben, die nicht manipuliert werden können. Dies gibt der Laufzeit die Freiheit, beispielsweise zugewiesene Objekte im Speicher zu verschieben , was für eine leistungsstarke GC-Implementierung von entscheidender Bedeutung ist.
Für die Aufzeichnung verwendet keine moderne GC-Implementierung Referenzzählung , so dass es sich vollständig um einen roten Hering handelt. Moderne GCs verwenden die Generationssammlung, bei der neue Zuordnungen im Wesentlichen genauso behandelt werden wie Stapelzuordnungen in einer Sprache wie C ++, und neu zugewiesene Objekte, die noch am Leben sind, in regelmäßigen Abständen in einen separaten "Überlebensraum" und in eine gesamte Generation verschoben werden von Objekten wird sofort freigegeben.
Dieser Ansatz hat Vor- und Nachteile: Der Vorteil ist, dass Heap-Zuweisungen in einer Sprache, die GC unterstützt, genauso schnell sind wie Stack-Zuweisungen in einer Sprache, die GC nicht unterstützt, und der Nachteil ist, dass Objekte bereinigt werden müssen, bevor sie zerstört werden erfordern einen separaten Mechanismus (z. B. das using
Schlüsselwort von C # ) oder ihr Bereinigungscode wird nicht deterministisch ausgeführt.
Beachten Sie, dass ein Schlüssel zu einem Hochleistungs-GC darin besteht, dass eine spezielle Klasse von Referenzen sprachlich unterstützt werden muss. C hat diese Sprachunterstützung nicht und wird es auch nie tun. Da C ++ eine Überladung von Operatoren aufweist, könnte es einen GC-Zeigertyp emulieren, obwohl dies sorgfältig durchgeführt werden müsste. Tatsächlich mussten Microsoft, als sie ihren C ++ - Dialekt erfanden, der unter der CLR (der .NET-Laufzeit) ausgeführt wurde, eine neue Syntax für "C # -Stilreferenzen" erfinden Foo^
, um sie von "C ++ - Stilreferenzen" zu unterscheiden. (zB Foo&
).
Was C ++ hat und was von C ++ - Programmierern regelmäßig verwendet wird, sind intelligente Zeiger , die eigentlich nur ein Referenzzählmechanismus sind. Ich würde die Referenzzählung nicht als "echte" GC betrachten, aber sie bietet viele der gleichen Vorteile auf Kosten einer geringeren Leistung als die manuelle Speicherverwaltung oder die echte GC, jedoch mit dem Vorteil einer deterministischen Zerstörung.
Am Ende des Tages läuft die Antwort wirklich auf ein Sprachgestaltungsmerkmal hinaus. C hat eine Wahl getroffen, C ++ hat eine Wahl getroffen, die es ermöglicht, mit C abwärtskompatibel zu sein, während es weiterhin Alternativen bietet, die für die meisten Zwecke gut genug sind, und Java und C # haben eine andere Wahl getroffen, die inkompatibel mit C ist, aber auch gut genug für die meisten Zwecke. Leider gibt es kein Patentrezept, aber wenn Sie mit den verschiedenen Auswahlmöglichkeiten vertraut sind, können Sie für jedes Programm, das Sie gerade erstellen möchten, das richtige auswählen.