garbage collection - Referenzen finden und updaten



  • Shade Of Mine schrieb:

    Ein GC kann Objekte verschieben, das kannst du in C++ nicht trivial machen. Die kosten für sowas sind enorm hoch.

    Zum Verschieben brauchst du aber doppelte statt einfacher Verweise, die Kosten für sowas sind enorm hoch.

    GC und RAII funktioniert gemeinsam.

    Wie das? So wie ich GCs kenne, sind sie u.a. gerade deshalb so effizient, weil sie keine Destruktoren aufrufen müssen.



  • fdfdg schrieb:

    GC und RAII funktioniert gemeinsam.

    Wie das? So wie ich GCs kenne, sind sie u.a. gerade deshalb so effizient, weil sie keine Destruktoren aufrufen müssen.

    Na, RAII ruft den Destruktor auf, der GC räumt den Speicher weg.



  • Danke für den link Shade of Mine, war hilfreich.

    fdfdg schrieb:

    Shade Of Mine schrieb:

    Ein GC kann Objekte verschieben, das kannst du in C++ nicht trivial machen. Die kosten für sowas sind enorm hoch.

    Zum Verschieben brauchst du aber doppelte statt einfacher Verweise, die Kosten für sowas sind enorm hoch.

    Ich glaub das stimmt so nicht zwingend. Ich habe zwar nirgends gefunden wie das konkret gemacht wird, aber so könnte man es ohne doppelte Verweise (jedenfalls während der normalen Ausführung) und O(n) machen:
    Bevor man mit mark-and-compact anfängt, erstellt man für jeden n-byte Speicherblock eine Datenstruktur, die alte Adressen auf neue mappen kann.
    Man kann zu einer beliebigen Speicheradresse im alten Speicherbereich die address map durch array indexing finden, d.h. in konstanter Zeit. Das macht man einfach, indem man das offset zum Beginn verwendeten Speichers ermittelt und durch n (die Größe eines Speicherblocks) teilt.
    Das suchen einer Adresse in einer address map hat wegen dem beschränkten Speicherbereich jeder map einen Maximaldauer, daher ist auch diese Operation O(1). (Welche Datenstruktur man nimmt ist nicht eindeutig, der konstante overhead beim suchen und Speichern spielt hier eine große Rolle)
    Wenn man ein Objekt kopiert, speichert man in der zugehörigen address map, wo das Objekt hinkopiert wurde. Nach dem compacting wird dann für jede Referenz auf dem stack und im neuen Speicherbereich in den address maps nach dem neuen Speicherort gesucht.

    GC und RAII funktioniert gemeinsam.

    Wie das? So wie ich GCs kenne, sind sie u.a. gerade deshalb so effizient, weil sie keine Destruktoren aufrufen müssen.

    In c++ kann man Objekte auf den stack oder den heap legen. Es wäre genauso gut vorstellbar, Objekte in einer anderen Sprache auf den stack oder in den gc zu legen.



  • Vielleicht ganz interessant: http://herbsutter.com/2011/10/25/garbage-collection-synopsis-and-c/
    http://dlang.org/garbage.html (Auch wenn ich die Argumente hier kaum nachvollziehen kann..)

    Wobei ich mich frage: Was ist an new/delete eigentlich so langsam? Nur der Ring-Übergang?



  • Ethon schrieb:

    Na, RAII ruft den Destruktor auf, der GC räumt den Speicher weg.

    Und warum erzeugst du eine künstliche Unterscheidung zwischen Speicher und anderen Resourcen? Speicher ist eine Resource.



  • 314159265358979 schrieb:

    Ethon schrieb:

    Na, RAII ruft den Destruktor auf, der GC räumt den Speicher weg.

    Und warum erzeugst du eine künstliche Unterscheidung zwischen Speicher und anderen Resourcen? Speicher ist eine Resource.

    Man unterscheidet oder vereinheitlich es per Definition, daher kannst du diese Frage gern philisophisch klären...



  • 314159265358979 schrieb:

    Und warum erzeugst du eine künstliche Unterscheidung zwischen Speicher und anderen Resourcen? Speicher ist eine Resource.

    Speicher ist eine Ressource mit besonderen Eigenschaften. Ein Sonderfall. Der GC nutzt dieses zusätzliche Wissen aus.



  • Ethon schrieb:

    Na, RAII ruft den Destruktor auf, der GC räumt den Speicher weg.

    Dann skizzier das mal. RAII läuft ja in C++ deshalb so gut, weil für Stackobjekte gut Code generiert werden kann, der nach Verlassen des Scopes aufgerufen wird. Der Einsatz eines GC verträgt sich aber nicht gut mit der Nutzung des Stacks, deshalb hast du kein automatisches Aufräumen, ergo musst du herausfinden, welche Objekte nicht mehr gültig sind => Mark-And-Compact verliert seinen Vorteil.

    GorbGorb schrieb:

    fdfdg schrieb:

    Zum Verschieben brauchst du aber doppelte statt einfacher Verweise, die Kosten für sowas sind enorm hoch.

    Ich glaub das stimmt so nicht zwingend. Ich habe zwar nirgends gefunden wie das konkret gemacht wird, aber so könnte man es ohne doppelte Verweise (jedenfalls während der normalen Ausführung) und O(n) machen

    Klar kann man das machen, aber praktikabel ist das nicht, darum geht's ja.

    Dieses blinde Argumentieren Pro-GC ist genauso dumm wie strikt dagegen zu reden. Einen GC einzusetzen bedeutet eben auch, entsprechende, teils starke, Nachteile hinzunehmen. Damit ist ein GC je nach Einsatzzweck "besser" oder "schlechter". Das wissen auch Shade und hustbaer, die müssen aber nunmal PI widersprechen.



  • java ist unter anderem wegen dem gc so elendig langsam



  • fdfdg schrieb:

    Ethon schrieb:

    Na, RAII ruft den Destruktor auf, der GC räumt den Speicher weg.

    Dann skizzier das mal. RAII läuft ja in C++ deshalb so gut, weil für Stackobjekte gut Code generiert werden kann, der nach Verlassen des Scopes aufgerufen wird.

    In C++ gibt es nur "automatic storage duration", wo der Speicher für solche Objekte herkommt ist nicht festgeschrieben. Natürlich ist der Standard dahingehend ausgelegt, Compilern zu ermöglichen den Stack dafür zu nutzen. Der Compiler könnte den Speicher aber genau so gut vom GC holen wenn er meint dass das schlau ist.
    Der Destruktor kann ja nach wie vor deterministisch beim Verlassen des Scope aufgerufen werden.

    Der Einsatz eines GC verträgt sich aber nicht gut mit der Nutzung des Stacks, deshalb hast du kein automatisches Aufräumen, ergo musst du herausfinden, welche Objekte nicht mehr gültig sind => Mark-And-Compact verliert seinen Vorteil.

    z.T. Stack siehe oben.

    Ansonsten...
    In Sprachen ohne GC musst du dafür sorgen, dass keine Referenzen auf Objekte die es nicht mehr gibt verwendet werden. Wenn man dabei einen Fehler macht, gibt es undefined behaviour. Das gilt für "non-RAII" Objekte und natürlich genau so für RAII-Objekte.

    Wenn du ein Programm nimmst das ohne GC korrekt funktioniert, und RAII einsetzt, dann wird es auch mit GC korrekt funktionieren und RAII einsetzen.

    Der einzige Unterschied ist dann, dass der Speicher der RAII Objekte erst später freigegeben wird. Der Aufruf des Destruktors bleibt dort wo er immer war. Man bekommt sogar noch einen Vorteil: die Referenzen (die man nicht haben/verwenden sollte) auf "freigegebene" Objekte zeigen jetzt nicht mehr ins Nirvana, sondern auf Objekte der jeweiligen Klasse die sich in einem (u.U. wohldefinierten) Zombie-Zustand befinden.
    Statt undefined behaviour kann man dann kontrolliert das Programm abbrechen (oder eine Exception werfen oder was auch immer).

    Probleme ergeben sich erst, wenn man vom GC jetzt zusätzlich noch fordert dass er deterministisch und ohne Verzögerung das "end of life" von Objekten mit shared ownership erkennt. Damit eben alle Objekte die Resourcen besitzen automatisch, deterministisch und sofort freigegeben werden können (wie man es z.B. von shared_ptr haben kann so lange man keine Zyklen baut). Das ist aber etwas was ein GC noch nie konnte, und was man auch vorher ohne GC nicht konnte. Die Forderung ist also unvernünftig.
    (Bzw. gleich gut wie shared_ptr kann es der GC natürlich können, Python macht das z.B. so (bzw. hat es zumindest in einigen Versionen so gemacht))

    Ansonsten... das ursprüngliche Thema war dass das ewige try-finally schreiben nervt, und das manuelle Aufrufen des Finalizers für Member nervt. Was jetzt mit dem GC wenig (nix) zu tun hat, sondern nur damit ob die Sprache die man verwendet eine Syntax dafür anbietet.

    z.B. in C++/CLI muss ich weder try-finally verwenden um Objekte mit "automatic storage duration" zu finalisieren, noch muss ich den Finalizer für Basisklassen oder Member manuell aufrufen.

    Wo ist jetzt also das Problem?

    fdfdg schrieb:

    Dieses blinde Argumentieren Pro-GC ist genauso dumm wie strikt dagegen zu reden. Einen GC einzusetzen bedeutet eben auch, entsprechende, teils starke, Nachteile hinzunehmen. Damit ist ein GC je nach Einsatzzweck "besser" oder "schlechter". Das wissen auch Shade und hustbaer, die müssen aber nunmal PI widersprechen.

    Ich argumentiere nicht "blind für GC".
    Wenn du wirklich meinst dass die Beiträge von Pi in dieser Diskussion irgend einen Wert haben, oder dass er nicht "strikt dagegen redet"... 🙄


Anmelden zum Antworten