Skip to content

Garbage Collection

Memory Safety

  • Bei uns werden Metadaten vom .NET-GC abgeräumt
  • GC wird z.B. bei Webserver benötigt, wenn immer neue Objekte alloziert werden
  • Explizite Freigabe (mit delete) führt zu Dangling Pointers (zu frühe Freigabe) und Memory Leaks (zu späte / keine Freigabe)

Garbage Collection

  • Laufzeitsystem kümmert sich um die Freigabe
  • Es gibt mehrere Techniken dazu
  • Garbage = Objekte, die nicht mehr erreichbar sind und daher nicht mehr gebraucht werden

Reference Counting

  • Naive Variante von GC
  • z.B. von Objective C implementiert, bei C++ shared pointers
  • Idee: Eingehende Referenzen von einem Objekt zählen
    • Wenn die Zahl = 0 -> Ist Garbage
    • Bei Zyklischen Abhängigkeiten ist Garbage = Reference Count 0 nicht gegeben
  • Updates sind teuer
    • Die Reference Counts sind "shared resources", d.h. sie müssen atomar geschrieben werden
  • Zyklische Strukturen werden nie zu Garbage, da sie sich immer gegenseitig (bzw. zyklisch) referenzieren
    • = Memory Leak
    • Viele Strukturen sind zyklisch
    • Wird z.B. bei C++ mit weak_pointer gelöst
  • Vorteil: Deallokation ist deterministisch bei letzter Dereferenzierung

Garbage Collector

  • Heap wird analysiert und Garbage freigegeben
  • Heap ist ein flacher Graph
  • Läuft nicht-deterministisch
  • Garbage sind Nodes im Graph, die vom "Programm" nicht mehr erreichbar sind
  • Laufendes Programm ist "Root-Set"
  • Root-Set besteht aus allen Referenzen im aktiven Frame auf dem Call Stack

Mark & Sweep

  • Markiere alle transitiven erreichbaren Objekte
  • Sweep: Lösche alle nicht markierte Objekte
  • Mit Tiefensuche alle Objekte von einem Root-Objekt aus traversieren
  • Problem: GC kann bei tiefer Struktur selbst viel Speicher benötigen
  • Sweep: Linearer Scan über alle Blöcke im Heap
    • Nach dem Sweep die Markierung wieder resetten
  • Nun gibt es Lücken im Speicher (Fragmentierung)
    • Free list führen mit freien Speicherblöcken
    • Nächstes mal: Objekte verschieben

Detailaspekte

  • Programm darf eigentlich nicht laufen während dem Mark
    • Techniken für Concurrent GC, um keine Änderungen während dem Mark zu verpassen
  • Ausführungszeitpunkt
    • Spätestens, wenn der Heap voll sind
    • Oder prophylaktisch früher
  • Unser GC läuft sequentiell und exklusiv (nicht async), Programm ist unterbrochen
  • Root Set wird momentan vereinfacht auf das Main-Objekt

Woche 2 - Vertiefung

Stack Root Set

  • Erkenne Referenzen auf dem Call Stack
    • Activation Frame durchscanne
  • Lokale Variablen, Parameter (auch this pointer)
  • GC kann auch während einer Auswertung laufen, d.h. Pointer im Evaluation Stack beachten!

Finalizer

  • Üblicherweise kommen Objekte nur einmal in die Finalizer-Liste, d.h. sie können sich höchstens 1 Mal "resurrecten"

Weak References

  • Nicht im Sinne von z.B. C++ Weak References, sondern für einen "richtigen" GC, d.h. Zyklen sind kein Problem