Kommentare
- Wir ' haben dieses Semester ein Modul in der iPhone-Entwicklung. Nachdem ich 2 Jahre lang Apps für Android programmiert hatte, traf diese Frage den größten Teil der Klasse ziemlich hart. Erst jetzt sehen wir, wie viele Stunden Java uns tatsächlich erspart hat, indem wir keine bösen Speicherverwaltungsfehler aufspüren und keinen Kesselplattencode schreiben mussten.
- @NullUserException, da dies nicht ' Geben Sie keine Möglichkeit an, Speicher zurückzugewinnen, die so ziemlich einen GC impliziert.
- @ bizso09: Haben Sie sich ARC schon angesehen? Keine langsame / fette / nicht deterministische GC erforderlich, wenn Sie ' Systemunterstützung für die Referenzzählung erhalten haben: developer.apple. com / Technologies / ios5
- Die Antworten auf diese ziemlich gute Frage sind voller religiöser Scheiße.
- In C und C ++ ist es möglich, einen Zeiger zu nehmen und ihn zu werfen zu int und fügen Sie eine Nummer hinzu. Subtrahieren Sie später die Zahl vom int und setzen Sie das Ergebnis auf einen Zeiger zurück. Sie erhalten den gleichen Zeiger wie zuvor. Viel Glück bei der Implementierung eines GC, der diesen Speicher NICHT sammelt, während seine Adresse nur in der Variablen gespeichert ist, die auch einen anderen Wert hat. Ich weiß, dass das Beispiel albern ist, aber eine XOR-verknüpfte Liste verwendet etwas Ähnliches. Ich würde dies als Antwort posten, aber die Frage ist geschlossen.
Antwort
Für die Speicherbereinigung sind Datenstrukturen erforderlich Verfolgung von Zuordnungen und / oder Referenzzählung. Diese verursachen Speicheraufwand, Leistung und Komplexität der Sprache. C ++ ist so konzipiert, dass es „nah am Metall“ ist, mit anderen Worten, es bietet die leistungsstärkere Seite des Kompromisses gegenüber den Komfortfunktionen. Andere Sprachen machen diesen Kompromiss anders. Dies ist eine der Überlegungen bei der Auswahl einer Sprache, welche Betonung Sie bevorzugen.
Allerdings gibt es in C ++ viele Schemata für die Referenzzählung, die relativ leicht und leistungsfähig sind, sich jedoch in kommerziellen und Open Source-Bibliotheken befinden und nicht Teil der Sprache selbst sind. Die Referenzzählung zum Verwalten der Objektlebensdauer ist nicht mit der Speicherbereinigung identisch, behebt jedoch viele der gleichen Probleme und passt besser zum grundlegenden Ansatz von C ++.
Kommentare
- Ein sekundäres Problem ist, dass der GC nicht deterministisch ist. Das Objekt befindet sich möglicherweise noch lange nach dem Löschen des Programms durch " " it. Refcount-Lebenszyklen sind deterministisch. Wenn die letzte Referenz gelöscht wird, wird der Speicher gelöscht. Dies hat Auswirkungen nicht nur auf die Speichereffizienz, sondern auch auf das Debuggen. Ein häufiger Programmierfehler ist Das " Zombie " -Objekt, der theoretisch verworfene Referenzspeicher. GC maskiert diesen Effekt viel eher und erzeugt Fehler, die sind intermittierend und äußerst schwer zu finden.
- – modern gc ' verfolgt weder Zuordnungen noch Zählreferenzen. Sie erstellen ab Vorabend ein Diagramm Alles, was sich derzeit auf dem Stapel befindet, verdichtet und löscht einfach alles andere (vereinfacht), und GC führt normalerweise zu einer reduzierten Sprachkomplexität. Sogar der Leistungsvorteil ist fraglich.
- Äh, @kylben, der springende Punkt beim Einbinden eines automatischen GC in die Sprache ist, dass es unmöglich wird, auf Zombie-Objekte zu verweisen, weil der GC Gibt nur Objekte frei, auf die nicht verwiesen werden kann! Sie erhalten die Art von schwer zu verfolgenden Fehlern, über die Sie ' sprechen, wenn Sie Fehler bei der manuellen Speicherverwaltung machen.
- -1, GC zählt nicht Verweise. Abhängig von Ihrer Speichernutzung und Ihrem Zuordnungsschema kann ein GC außerdem schneller sein (mit einem Overhead bei der Speichernutzung). Das Argument über die Leistung ist also auch ein Trugschluss. Nur die Nähe zum Metall ist tatsächlich ein gültiger Punkt.
- Weder Java noch C # verwenden Referenzzählung: GC-Schemata, die auf Referenzzählung basieren, sind im Vergleich ziemlich primitiv und weisen eine viel schlechtere Leistung auf als moderne Müllsammler (hauptsächlich, weil sie Sie müssen Speicherschreibvorgänge ausführen, um die Referenzanzahl zu ändern, wenn Sie eine Referenz kopieren!)
Antwort
Genau genommen, In der Sprache C gibt es überhaupt keine Speicherverwaltung. malloc () und free () sind keine Schlüsselwörter in der Sprache, sondern nur Funktionen, die aus einer Bibliothek aufgerufen werden.Diese Unterscheidung mag jetzt pedantisch sein, da malloc () und free () Teil der C-Standardbibliothek sind und von jeder standardkonformen Implementierung von C bereitgestellt werden. Dies war jedoch in der Vergangenheit nicht immer der Fall.
Warum sollten Sie eine Sprache ohne Standard für die Speicherverwaltung wünschen? Dies geht auf Cs Ursprünge als „tragbare Baugruppe“ zurück. Es gibt viele Fälle von Hardware und Algorithmen, die von speziellen Speicherverwaltungstechniken profitieren oder diese sogar erfordern können. Soweit ich weiß, gibt es keine Möglichkeit, die native Speicherverwaltung von Java vollständig zu deaktivieren und durch Ihre eigene zu ersetzen. Dies ist in einigen Situationen mit hoher Leistung und minimalen Ressourcen einfach nicht akzeptabel. C bietet nahezu vollständige Flexibilität, um genau die Infrastruktur auszuwählen Ihr Programm wird verwendet. Der bezahlte Preis ist, dass die C-Sprache nur sehr wenig Hilfe beim Schreiben von korrektem, fehlerfreiem Code bietet.
Kommentare
- +1 eins für die insgesamt gute Antwort, aber auch speziell für " Der bezahlte Preis ist, dass die C-Sprache nur sehr wenig Hilfe beim Schreiben des richtigen, fehlerfreien Codes
- C hat zwar eine Speicherverwaltung – aber es funktioniert nur, sodass die Leute es kaum bemerken. Es gibt ' statischen Speicher, Register und die Bis Sie mit der Zuweisung aus dem Heap beginnen, ' ist alles in Ordnung und gut. ' ist die Heap-Zuordnung, die die Dinge durcheinander bringt . Wie Für Java kann jeder seine eigene Java-Laufzeit schreiben – es gibt ' eine große Auswahl, einschließlich des so genannten " System ' s Java ". .NET kann so ziemlich alles, was C kann – es bleibt nur hinter den nativen Funktionen von C ++ ' zurück (z. B. werden Klassen nur in .NET verwaltet). Natürlich haben Sie auch C ++. NET, das alles hat, was C ++ macht, und alles, was .NET macht.
- @Luaan Ich ' würde sagen, dass ' ist eine sehr großzügige Definition für " Speicherverwaltung " " Bis Sie anfangen, aus dem Heap zuzuweisen, geht es Ihnen ' gut und gut. Es ist ' die Heap-Zuordnung, die die Dinge durcheinander bringt ", das ' wie gesagt Ein Auto ist ein perfektes Flugzeug, es kann einfach nicht ' fliegen.
- @ CharlesE.Grant Nun, eine rein funktionale Sprache kann alles damit machen Art der Speicherverwaltung. Nur weil die Heap-Zuweisung in einigen Anwendungsfällen ein guter Kompromiss ist, bedeutet ' nicht, dass ' der Benchmark für alle Sprachen / Laufzeiten ist . ' ist nicht so, dass die Speicherverwaltung nicht mehr " Speicherverwaltung " ist, nur weil es ' ist einfach, unkompliziert und hinter den Kulissen versteckt. Das Entwerfen der statischen Speicherzuweisung ist nach wie vor eine Speicherverwaltung, ebenso wie eine gute Verwendung des Stapels und aller anderen verfügbaren Elemente.
- " Jede standardkonforme Implementierung " ist nicht wahr, nur für die Implementierung einer standardkonformen Hostumgebung. Einige Plattformen / Standardbibliotheken, die meisten für eingebettete 8- oder 16-Bit-Mikrocontroller, bieten nicht
malloc()
oderfree()
. (Beispiel sind MLAP-Compiler für PIC)
Antwort
Die eigentliche Antwort ist, dass dies der einzige Weg ist Ein sicherer und effizienter Garbage Collection-Mechanismus besteht darin, Unterstützung auf Sprachebene für undurchsichtige Referenzen zu haben. (Oder umgekehrt ein Mangel an Unterstützung auf Sprachebene für die direkte Speichermanipulation.)
Java und C # können dies tun, da sie spezielle Referenztypen haben, die nicht manipuliert werden können. Dies gibt der Laufzeit die Freiheit, Dinge wie zugewiesene Objekte im Speicher zu verschieben, was für eine leistungsstarke GC-Implementierung von entscheidender Bedeutung ist
Für den Datensatz verwendet keine moderne GC-Implementierung die Referenzzählung , sodass dies vollständig rot ist Hering. Moderne GCs verwenden die Generationssammlung, bei der neue Zuordnungen im Wesentlichen genauso behandelt werden wie Stapelzuweisungen in einer Sprache wie C ++. Anschließend werden regelmäßig neu zugewiesene Objekte, die noch am Leben sind, in einen separaten „Überlebensbereich“ und eine gesamte Generation verschoben von Objekten wird sofort freigegeben.
Dieser Ansatz hat Vor- und Nachteile: Der Vorteil ist, dass Heap-Zuweisungen in einer Sprache, die GC unterstützt, so schnell sind wie Stapelzuweisungen in einer Sprache, die GC nicht unterstützt, und der Nachteil ist, dass Objekte, die vor der Zerstörung eine Bereinigung durchführen müssen, entweder einen separaten Mechanismus benötigen (z. B. C #“ s using
keyword) oder ihr Bereinigungscode wird nicht deterministisch ausgeführt.
Beachten Sie, dass ein Schlüssel für einen Hochleistungs-GC darin besteht, dass eine spezielle Referenzklasse sprachlich unterstützt werden muss. C hat diese Sprachunterstützung nicht und wird es auch nie tun. Da C ++ über eine Operatorüberladung verfügt, könnte es einen GC-Zeigertyp emulieren, obwohl dies sorgfältig durchgeführt werden müsste. Als Microsoft seinen C ++ – Dialekt erfand, der unter der CLR (der .NET-Laufzeit) ausgeführt werden sollte, mussten sie eine neue Syntax für „C # -Stilreferenzen“ erfinden (z. B. Foo^
) um sie von „C ++ – Stilreferenzen“ zu unterscheiden (z. B. Foo&
).
Was C ++ hat und was regelmäßig von C ++ – Programmierern verwendet wird, ist 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 langsameren Leistung als die manuelle Speicherverwaltung oder die echte GC, jedoch mit dem Vorteil einer deterministischen Zerstörung. P. >
Letztendlich läuft die Antwort wirklich auf ein Sprachdesign-Feature hinaus. C traf eine Wahl, C ++ traf eine Wahl, die es ermöglichte, abwärtskompatibel mit C zu sein und dennoch Alternativen bereitzustellen, für die es gut genug ist Die meisten Zwecke, und Java und C # haben eine andere Wahl getroffen, die nicht mit C kompatibel ist, aber auch für die meisten Zwecke gut genug ist. Leider gibt es keine Silberkugel, aber wenn Sie mit den verschiedenen Möglichkeiten vertraut sind, können Sie die richtige auswählen Für jedes Programm, das Sie gerade erstellen möchten.
Kommentare
- Dies ist die eigentliche Antwort auf die Frage
- Für Im C ++ – Teil sollten Sie sich heutzutage std :: unique_ptr und std :: move ansehen 🙂
- kein modernes GC-Implem Entation verwendet Referenzzählung : cPython verwendet sowohl die Referenzzählung als auch die automatische Erfassung .
- @ Mike76: Auf der Zuordnungsseite arbeitet ein GC-Zuweiser ungefähr so schnell wie die Stapelzuweisung, und der GC kann Tausende von Objekten gleichzeitig freigeben. Unabhängig davon, was Sie mit einer Ref-Counting-Implementierung tun, sind Zuweisung und Freigabe niemals schneller als
malloc
undfree
. Ja, ein GC kann wesentlich schneller sein. (Beachten Sie, dass ich sagte, dass " " sein kann – natürlich wird die genaue Leistung jedes Programms von vielen Faktoren beeinflusst.) - keine moderne GC-Implementierung verwendet Referenzzählung Swift verwendet automatische Referenzzählung.
Antwort
Weil bei Verwendung der Leistung von C ++ keine Notwendigkeit besteht.
Herb Sutter:“ Ich habe seit Jahren kein Löschen mehr geschrieben. “
siehe Schreiben von modernem C ++ – Code: Wie sich C ++ im Laufe der Jahre entwickelt hat 21:10
Es kann viele überraschen erfahrene C ++ – Programmierer.
Kommentare
- Interessant. Mein Lesematerial für heute.
- Bah, ein Video. Aber trotzdem schon interessant.
- interessantes Video. 21 Minuten und 55 Minuten waren die besten Teile. Schade, dass die WinRT-Aufrufe immer noch C ++ / CLI-Bumpf waren.
- @ dan04: Das ' ist wahr. Wenn Sie jedoch in C schreiben, erhalten Sie das, wonach Sie fragen.
- Das Verwalten der intelligenten Zeiger ist nicht anspruchsvoller, als sicherzustellen, dass Sie nicht ' t unnötige Referenzen in einer Müllsammelumgebung haben. Da GC ' Ihre Gedanken nicht lesen kann, ist ' auch keine Magie.
Antwort
„Alle“ Ein Garbage Collector ist ein Prozess, der regelmäßig überprüft, ob sich nicht referenzierte Objekte im Speicher befinden und ob sie gelöscht werden. (Ja, ich weiß, dass dies eine grobe Vereinfachung ist). Dies ist keine Eigenschaft der Sprache, sondern des Frameworks.
Es gibt Garbage Collectors, die für C und C ++ geschrieben wurden – diese zum Beispiel
Ein Grund, warum man der Sprache nicht „hinzugefügt“ wurde, könnte das schiere Volumen des vorhandenen Codes sein, der ihn niemals verwenden würde, da sie ihren eigenen Code für die Speicherverwaltung verwenden. Ein anderer Grund könnte dies sein Sei es, dass die in C und C ++ geschriebenen Anwendungstypen nicht den mit einem Garbage Collection-Prozess verbundenen Overhead benötigen.
Kommentare
- Aber zukünftige Programme geschrieben würde anfangen, den Müllsammler zu benutzen, nein?
- Während die Garbage Collection theoretisch unabhängig von einer Programmiersprache ist, ist es ziemlich schwierig, einen nützlichen GC für C / C ++ zu schreiben, und es ist sogar unmöglich, einen narrensicheren zu erstellen (mindestens so narrensicher wie Java ' s) – Der Grund, warum Java dies ausführen kann, liegt darin, dass es in einer kontrollierten virtualisierten Umgebung ausgeführt wird. Umgekehrt ist die Java-Sprache für GC konzipiert, und es fällt Ihnen ' schwer, einen Java-Compiler zu schreiben, der ' GC nicht ausführt
- @tdammers: Ich bin damit einverstanden, dass die Speicherbereinigung von der Sprache unterstützt werden muss, um möglich zu sein. Der Hauptpunkt ist jedoch nicht die Virtualisierung und die kontrollierte Umgebung, sondern die strikte Eingabe. C und C ++ sind schwach typisiert, so dass sie Dinge wie das Speichern von Zeigern in ganzzahligen Variablen, das Rekonstruieren von Zeigern aus Offsets und solche Dinge ermöglichen, die den Kollektor daran hindern, zuverlässig zu sagen, was erreichbar ist (C ++ 11 verbietet es den späteren, dies zumindest zuzulassen konservative Sammler). In Java wissen Sie immer, was eine Referenz ist, sodass Sie sie genau erfassen können, auch wenn sie in native kompiliert wurde.
- @Thorbj ø rnRavnAndersen: Ich kann eine schreiben gültiges C-Programm, das Zeiger so speichert, dass kein Garbage Collector sie jemals finden kann. Wenn Sie dann einen Garbage Collector an
malloc
undfree
anschließen, wird mein korrektes Programm beschädigt. - @Thorbj ø rnRavnAndersen: Nein, ich würde '
free
nicht aufrufen, bis ich damit fertig bin . Ihr vorgeschlagener Garbage Collector, der nicht ' den Speicher freigibt, bis ich explizitfree
aufrufe, ist nicht ' ta Garbage Collector überhaupt.
Antwort
C wurde in einer Zeit entwickelt, in der die Garbage Collection kaum möglich war eine Option. Es war auch für Anwendungen gedacht, bei denen die Speicherbereinigung im Allgemeinen nicht funktioniert – Bare-Metal-Umgebungen in Echtzeit mit minimalem Arbeitsspeicher und minimaler Laufzeitunterstützung. Denken Sie daran, dass C die Implementierungssprache für das erste Unix war, das auf einem pdp-11 mit 64 * K * Bytes Speicher ausgeführt wurde. C ++ war ursprünglich eine Erweiterung von C – die Wahl wurde bereits getroffen, und es ist sehr schwierig, die Speicherbereinigung auf eine vorhandene Sprache zu übertragen. Dies ist die Art von Dingen, die vom Erdgeschoss aus eingebaut werden müssen.
Antwort
Ich habe nicht die genauen Anführungszeichen, aber sowohl Bjarne als auch Herb Sutter sagen etwas in der Richtung:
C ++ benötigt keinen Garbage Collector, da es keinen Müll gibt.
In der Moderne In C ++ verwenden Sie intelligente Zeiger und haben daher keinen Müll.
Kommentare
- Was sind intelligente Zeiger?
- wenn es das wäre Einfach gesagt, niemand hätte einen GC implementiert.
- @deadalnix: Richtig, weil niemand jemals etwas übermäßig Kompliziertes, Langsames, Aufgeblähtes oder Unnötiges implementiert. Die gesamte Software ist jederzeit zu 100% effizient, oder?
- @deadalnix – Der C ++ – Ansatz für die Speicherverwaltung ist neuer als Garbage Collectors. RAII wurde von Bjarne Stroustrup für C ++ erfunden. Die Destruktorbereinigung ist eine ältere Idee, aber die Regeln zur Gewährleistung der Ausnahmesicherheit sind der Schlüssel. Ich ' weiß nicht genau, wann die Idee selbst zum ersten Mal beschrieben wurde, aber der erste C ++ – Standard wurde 1998 fertiggestellt und Stroustrups " Design und Entwicklung von C ++ " wurde ' erst 1994 veröffentlicht, und Ausnahmen waren eine relativ neue Ergänzung zu C ++ – nach der Veröffentlichung des " Kommentiertes C ++ – Referenzhandbuch " im Jahr 1990, glaube ich. GC wurde 1959 für Lisp erfunden.
- @deadalnix – Ist Ihnen bekannt, dass mindestens eine Java-VM einen Referenzzähl-GC verwendete, der (fast) mit C ++ – RAII unter Verwendung einer Smart-Pointer-Klasse implementiert werden konnte – gerade weil es für Multithread-Code effizienter war als für vorhandene VMs? Siehe www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf. Ein Grund, warum Sie ' dies in C ++ in der Praxis nicht sehen, ist die übliche GC-Sammlung – sie kann Zyklen sammeln, aber ' kann nicht wählen Eine sichere Destruktorreihenfolge bei Vorhandensein von Zyklen und kann daher keine zuverlässige Destruktorbereinigung gewährleisten.
Antwort
Sie Fragen Sie, warum diese Sprachen nicht aktualisiert wurden, um einen optionalen Garbage Collector einzuschließen.
Das Problem bei der optionalen Garbage Collection besteht darin, dass Sie keinen Code mischen können, der die verschiedenen Modelle verwendet. Das heißt, wenn ich Code schreibe, der davon ausgeht, dass Sie einen Garbage Collector verwenden, können Sie ihn nicht in Ihrem Programm verwenden, in dem die Garbage Collection deaktiviert ist. Wenn Sie dies tun, wird er überall auslaufen.
Antwort
Es gibt verschiedene Probleme, darunter …
- Obwohl GC vor C ++ und möglicherweise vor C erfunden wurde, wurden sowohl C als auch C ++ implementiert, bevor GCs allgemein als praktisch akzeptiert wurden.
- Sie können a nicht einfach implementieren GC-Sprache und -Plattform ohne zugrunde liegende Nicht-GC-Sprache.
- Obwohl GC für typischen Anwendungscode, der in typischen Zeiträumen usw. entwickelt wurde, nachweislich effizienter als Nicht-GC ist, gibt es Probleme, bei denen mehr Entwicklungsaufwand ein guter Handel ist -off und die spezialisierte Speicherverwaltung übertreffen eine Allzweck-GC. Außerdem ist C ++ in der Regel nachweislich effizienter als die meisten GC-Sprachen, auch ohne zusätzlichen Entwicklungsaufwand.
- GC ist nicht allgemein sicherer als RAII im C ++ – Stil Mit RAII können andere Ressourcen als der Speicher automatisch bereinigt werden, da zuverlässige und zeitnahe Destruktoren unterstützt werden. Diese können aufgrund von Problemen mit Referenzzyklen nicht mit herkömmlichen GC-Methoden kombiniert werden.
- GC-Sprachen haben ihre eigenen Eigenschaften Arten von Erinnerung Lecks, insbesondere in Bezug auf Speicher, der nie wieder verwendet wird, bei denen jedoch vorhandene Referenzen vorhanden waren, die nie auf Null gesetzt oder überschrieben wurden. Die Notwendigkeit, dies explizit zu tun, unterscheidet sich im Prinzip nicht von der Notwendigkeit,
delete
oderfree
explizit zu tun. Der GC-Ansatz hat immer noch einen Vorteil – keine baumelnden Referenzen – und die statische Analyse kann einige Fälle erfassen, aber auch hier gibt es „keine perfekte Lösung für alle Fälle.
Grundsätzlich teilweise“ Es geht um das Alter der Sprachen, aber es wird sowieso immer einen Platz für Nicht-GC-Sprachen geben – auch wenn es ein bisschen wie ein Nischenort ist. Und im Ernst, in C ++ ist das Fehlen von GC keine große Sache – Ihr Speicher wird anders verwaltet, aber es wird nicht nicht verwaltet.
Microsoft verwaltetes C ++ hat zumindest eine gewisse Fähigkeit, GC und Nicht-GC zu mischen GC in derselben Anwendung, die eine Mischung der Vorteile der einzelnen Anwendungen ermöglicht, aber ich habe nicht die Erfahrung zu sagen, wie gut dies in der Praxis funktioniert.
Rep-Whoring-Links zu verwandten Antworten von mir …
- https://stackoverflow.com/questions/1529679/how-do-you-program-safely-outside-of-a-managed-code-environment/1529731#1529731
- https://stackoverflow.com/questions/1424660/garbage-collection-vs-non-garbage-collection-programming-languages/1496547#1496547
- https://stackoverflow.com/questions/4984849/why-circular-referenced-objects-with-del-defined-are-uncollectable-in-python/4984934#4984934
- https://stackoverflow.com/questions/5009869/how-to-implement-garbage-collection-in-c/5009984#5009984
Antwort
Können Sie sich vorstellen, einen Gerätehandler in einer Sprache mit Speicherbereinigung zu schreiben? Wie viele Bits könnten in die Sprache kommen? Zeile, während der GC ausgeführt wurde?
Oder ein Betriebssystem? Wie können Sie die Garbage Collection starten, bevor Sie den Kernel überhaupt starten?
C ist für niedrige Pegel in der Nähe der Hardwareaufgaben ausgelegt. Das Problem? Ist es eine so schöne Sprache, dass es auch für viele übergeordnete Aufgaben eine gute Wahl ist? Die Sprachzaren sind sich dieser Verwendung bewusst, müssen jedoch vorrangig die Anforderungen von Gerätetreibern, eingebettetem Code und Betriebssystemen unterstützen.
Kommentare
- C gut für hohes Niveau? Ich schnaubte mein Getränk über meine Tastatur.
- Nun, er sagte " viele übergeordnete Aufgaben ". Er könnte Troll zählen (eins, zwei, viele …). Und er hat nicht ' tatsächlich höher gesagt als was. Abgesehen von Witzen ist es jedoch ' wahr – der Beweis dafür, dass viele bedeutende Projekte auf höherer Ebene in C erfolgreich entwickelt wurden. Möglicherweise gibt es bessere Möglichkeiten Jetzt für viele dieser Projekte, aber ein funktionierendes Projekt ist ein stärkerer Beweis als Spekulationen darüber, was gewesen sein könnte.
- Es gibt ' einige verwaltete Betriebssysteme und Sie funktionieren ziemlich gut. Wenn Sie das gesamte System verwalten, sinkt die Leistung durch die Verwendung von verwaltetem Code sogar noch weniger und ist in realen Szenarien schneller als nicht verwalteter Code. Das sind natürlich alle " Forschungsbetriebssystem " – es gibt ' so ziemlich nein Möglichkeit, sie mit vorhandenem nicht verwaltetem Code kompatibel zu machen und ein vollständig virtualisiertes nicht verwaltetes Betriebssystem innerhalb des verwalteten Betriebssystems zu erstellen. Microsoft hat jedoch irgendwann vorgeschlagen, Windows Server durch einen dieser Server zu ersetzen, da immer mehr Servercode in .NET geschrieben wird.
Antwort
Die kurze und langweilige Antwort auf diese Frage lautet, dass es für die Leute, die die Müllsammler schreiben, eine Sprache geben muss, die keinen Müll enthält. Es ist konzeptionell nicht einfach, eine Sprache zu haben, die gleichzeitig eine sehr genaue Kontrolle über das Speicherlayout ermöglicht, und , auf der ein GC ausgeführt wird.
Die andere Frage ist warum C und C ++ keine Garbage Collectors haben.Nun, ich weiß, dass C ++ einige von ihnen hat, aber sie sind nicht wirklich beliebt, weil sie gezwungen sind, sich mit einer Sprache zu befassen, die überhaupt nicht für die GC-Bearbeitung entwickelt wurde, und mit den Leuten, die C ++ noch verwenden Dieses Zeitalter ist nicht wirklich die Art, in der ein GC fehlt.
Anstatt GC zu einer alten Sprache ohne GC-Ed hinzuzufügen, ist es tatsächlich einfacher, eine neue Sprache zu erstellen, die die meisten Sprachen enthält Dieselbe Syntax bei der Unterstützung eines GC. Java und C # sind gute Beispiele dafür.
Kommentare
- Irgendwo auf programmers.se oder SO gibt es ' Ich behaupte, jemand hat mir mitgeteilt, dass jemand an einem selbst-Bootstrapping-Ding mit Müllsammlung gearbeitet hat – IIRC implementiert die VM im Grunde genommen in einer GC-Sprache, wobei eine Bootstrapping-Teilmenge verwendet wird, um den GC selbst zu implementieren Ich habe den Namen vergessen. Als ich ihn mir ansah, stellte sich heraus, dass sie ' im Grunde nie den Sprung von der Teilmenge ohne GC zur Arbeits-GC-Ebene geschafft hatten ist im Prinzip möglich, aber AFAIK wurde in der Praxis nie erreicht – es ' ist sicherlich ein Fall, Dinge auf die harte Tour zu machen.
- @ Steve314: I. ' Ich würde das gerne sehen, wenn Sie sich jemals daran erinnern, wo Sie es gefunden haben!
- haben es gefunden! Siehe die Kommentare zu stackoverflow.com/questions/3317329/… , die sich auf die Klein-VM beziehen. Ein Teil des Problems, es zu finden – die Frage wurde geschlossen.
- Übrigens – Ich kann meine Kommentare anscheinend nicht mit @missingno beginnen – was gibt es?
- @ steve314: Nachdem ich die Antwort darauf geschrieben habe Thread angehängt ist, ich erhalte bereits eine Benachrichtigung für alle Kommentare. Das Ausführen eines @ -Posts wäre in diesem Fall überflüssig und wird von SE nicht zugelassen (' frage mich jedoch nicht warum ). (Die eigentliche Ursache ist jedoch, dass meine Nummer fehlt.)
Antwort
Die Speicherbereinigung ist grundsätzlich nicht kompatibel mit a Systemsprache, die zum Entwickeln von Treibern für DMA-fähige Hardware verwendet wird.
Es ist durchaus möglich, dass der einzige Zeiger auf ein Objekt in einem Hardwareregister in einem Peripheriegerät gespeichert wird. Da der Garbage Collector es nicht weiß In diesem Zusammenhang würde es denken, dass das Objekt nicht erreichbar ist, und es sammeln.
Dieses Argument gilt doppelt für die Komprimierung von GC. Selbst wenn Sie darauf geachtet hätten, speicherinterne Verweise auf Objekte zu pflegen, die von Hardware-Peripheriegeräten verwendet werden, würde der GC beim Verschieben des Objekts nicht wissen, wie der im Konfigurationsregister für Peripheriegeräte enthaltene Zeiger aktualisiert werden soll.
Also Jetzt benötigen Sie eine Mischung aus unbeweglichen DMA-Puffern und GC-verwalteten Objekten, was bedeutet, dass Sie alle Nachteile von beiden haben.
Kommentare
- Wohl alle Nachteile von beiden, aber weniger Fälle von jedem Nachteil und das gleiche für die Vorteile. Es ist klar, dass es komplexer ist, mehr Arten der Speicherverwaltung zu erledigen, aber es kann auch Komplexität vermieden werden, indem Sie für jeden Kurs in Ihrem Code das richtige Pferd auswählen. Unwahrscheinlich, stelle ich mir vor, aber ' gibt es dort eine theoretische Lücke. Ich ' habe zuvor darüber spekuliert, GC und Nicht-GC in derselben Sprache zu mischen, aber nicht für Gerätetreiber – eher für eine überwiegend GC-Anwendung, aber mit einigen manuell speicherverwalteten Low-Werten Datenstrukturbibliotheken auf Ebene.
- @ Steve314: Würden Sie nicht ' sagen, dass das Erinnern daran, welche Objekte manuell freigegeben werden müssen, genauso mühsam ist wie das Erinnern, alles freizugeben? (Natürlich können intelligente Zeiger bei beiden helfen, sodass keiner der beiden ein großes Problem darstellt.) Und Sie benötigen unterschiedliche Pools für manuell verwaltete Objekte im Vergleich zu gesammelten / komprimierbaren Objekten, da die Komprimierung nicht ' t ist funktionieren gut, wenn feste Gegenstände überall verstreut sind. Also viel zusätzliche Komplexität für nichts.
- Nicht, wenn ' eine klare Trennung zwischen dem Code auf hoher Ebene, bei dem es sich ausschließlich um GC handelt, und dem Code auf niedriger Ebene besteht Code, der aus GC ausscheidet. Ich habe die Idee vor einigen Jahren hauptsächlich bei der Betrachtung von D entwickelt, mit der Sie sich von GC abmelden können, aber ' nicht zulassen, dass Sie sich wieder anmelden. Nehmen Sie zum Beispiel eine B + -Baumbibliothek . Der Container als Ganzes sollte GC sein, die Datenstrukturknoten jedoch wahrscheinlich nicht – es ist ' effizienter, einen benutzerdefinierten Scan nur durch die Blattknoten durchzuführen, als den GC a rekursive Suche durch die Zweigknoten. Dieser Scan muss jedoch die enthaltenen Elemente an den GC melden.
- Der Punkt ist, dass ' eine enthaltene Funktionalität ist. Die Behandlung der B + -Baumknoten als spezielle WRT-Speicherverwaltung unterscheidet sich nicht von der Behandlung als spezielle WRT als B + -Baumknoten. ' ist eine gekapselte Bibliothek, und der Anwendungscode ' muss nicht wissen, dass das GC-Verhalten umgangen / speziell behandelt wurde.Abgesehen davon, dass dies zumindest zu diesem Zeitpunkt in D unmöglich war – wie gesagt, keine Möglichkeit, sich wieder anzumelden und die enthaltenen Elemente als potenzielle GC-Wurzeln an den GC zu melden.
Antwort
Weil C & C ++ relativ einfache Sprachen sind, die für allgemeine Zwecke gedacht sind, auch zum Beispiel auf einem 16-Bit-Prozessor mit 1 MB Speicher in einem eingebetteten System auszuführen, der es sich nicht leisten konnte, Speicher mit gc zu verschwenden.
Kommentare
- " Eingebettetes System "? Zum Zeitpunkt der Standardisierung von C (1989) musste es in der Lage sein, PCs zu handhaben. i> mit 1 MB Speicher.
- Ich stimme zu, ich habe ein aktuelleres Beispiel angeführt.
- 1 MB ??? Holy schmoley, wer würde jemals so viel RAM brauchen? < / billGates >
Antwort
Es gibt Garbage Collectors in C ++ und C. Ich bin mir nicht sicher, wie das in C funktioniert, aber In C ++ können Sie RTTI nutzen, um Ihr Objektdiagramm dynamisch zu erkennen und für die Speicherbereinigung zu verwenden.
Meines Wissens können Sie kein Java schreiben ohne Müllsammler. Eine kleine Suche ergab this .
Der Hauptunterschied zwischen Java und C / C ++ besteht darin, dass Sie in C / C ++ immer die Wahl haben Während in Java häufig keine Optionen vorgesehen sind.
Kommentare
- Und auch, dass die dedizierten Garbage Collectors besser implementiert und effizienter sind und passen besser in die Sprache. 🙂
- Nein, Sie können ' RTTI nicht verwenden, um das Objektdiagramm in C / C ++ dynamisch zu erkennen: It ' sind die einfachen alten Datenobjekte, die alles verderben. In einem einfachen alten Datenobjekt sind einfach keine RTTI-Informationen gespeichert, die es einem Garbage Collector ermöglichen würden, zwischen Zeigern und Nichtzeigern innerhalb dieses Objekts zu unterscheiden. Schlimmer noch, Zeiger müssen nicht auf jeder Hardware perfekt ausgerichtet sein. Bei einem 16-Byte-Objekt gibt es also 9 mögliche Speicherorte, an denen ein 64-Bit-Zeiger gespeichert werden kann, von denen nur zwei nicht ' t überlappen.
Antwort
Es ist ein Kompromiss zwischen Leistung und Sicherheit.
Es gibt keine Garantie dafür, dass Ihr Müll in Java gesammelt wird Es kann sein, dass es lange Zeit Speicherplatz verbraucht, während das Scannen nach nicht referenzierten Objekten (dh Müll) auch länger dauert als das explizite Löschen oder Freigeben eines nicht verwendeten Objekts.
Der Vorteil ist natürlich, dass Man kann eine Sprache ohne Zeiger oder ohne Speicherlecks erstellen, daher ist es wahrscheinlicher, dass man korrekten Code erzeugt.
Diese Debatten können manchmal einen leichten „religiösen“ Rand haben – seien Sie gewarnt!
Antwort
Hier ist eine Liste der inhärenten Probleme von GC, die es in einer Systemsprache wie C unbrauchbar machen:
-
Der GC muss unterhalb der Ebene des Codes ausgeführt werden, dessen Objekte er verwaltet. In einem Kernel gibt es einfach keine solche Ebene.
-
Ein GC muss den verwalteten Code von Zeit zu Zeit stoppen. Überlegen Sie nun, was passieren würde, wenn es Ihrem Kernel das antun würde. Die gesamte Verarbeitung auf Ihrem Computer wird beispielsweise für eine Millisekunde angehalten, während der GC alle vorhandenen Speicherzuordnungen durchsucht. Dies würde alle Versuche zum Erstellen von Systemen unter strengen Echtzeitanforderungen zunichte machen.
-
Ein GC muss in der Lage sein, zwischen Zeigern und Nichtzeigern zu unterscheiden. Das heißt, es muss in der Lage sein, jedes existierende Speicherobjekt zu betrachten und eine Liste von Offsets zu erstellen, in denen seine Zeiger gefunden werden können.
Diese Entdeckung muss perfekt sein: Der GC muss in der Lage sein alle Hinweise zu verfolgen, die es entdeckt. Wenn es ein falsches Positiv dereferenziert, würde es wahrscheinlich abstürzen. Wenn ein falsches Negativ nicht erkannt wird, wird wahrscheinlich ein noch verwendetes Objekt zerstört, der verwaltete Code stürzt ab oder seine Daten werden unbemerkt beschädigt.
Dies erfordert unbedingt, dass Typinformationen in jedem einzelnen gespeichert werden Objekt vorhanden. Sowohl C als auch C ++ ermöglichen jedoch einfache alte Datenobjekte, die keine Typinformationen enthalten.
-
GC ist ein von Natur aus langsames Geschäft. Programmierer, die mit Java sozialisiert wurden Möglicherweise wird dies nicht erkannt, aber Programme können um Größenordnungen schneller sein, wenn sie nicht in Java implementiert sind. Einer der Faktoren, die Java langsam machen, ist GC. Dies verhindert, dass GC-Sprachen wie Java im Supercomputing verwendet werden Der Stromverbrauch kostet eine Million pro Jahr. Sie möchten nicht einmal 10% davon für die Speicherbereinigung bezahlen.
C und C ++ sind Sprachen, die zur Unterstützung erstellt wurden alle möglichen Anwendungsfälle. Und wie Sie sehen, werden viele dieser Anwendungsfälle durch die Speicherbereinigung ausgeschlossen. Um diese Anwendungsfälle zu unterstützen, kann C / C ++ nicht mit Müll gesammelt werden.