Garbage Collector (GC)

Garbage Collector är .NETs automatiska minneshanterar. Den spårar vilka objekt som används och frigör minnet för dem som inte längre nås.

När du läst detta ska du kunna

  • Förklara vad Garbage Collector är och vad den gör
  • Beskriva skillnaden mellan heap och stack
  • Förklara vad “rotreferens” innebär
  • Förstå varför du nästan aldrig behöver tänka på minne i C#

Stack och heap

C# använder två minnesutrymmen:

StackHeap
Vad lagrasVärdetyper (int, double, bool, struct), lokala variablerObjekt (klasser), strängar, arrayer
LivstidBestäms av scope — frigörs automatiskt när metoden returnerarBestäms av GC
HastighetSnabb — LIFO-stackLite långsammare
void Method()
{
int x = 42; // på stacken — frigörs när Metod() returnerar
var car = new Car(); // "car"-referensen på stacken, Car-objektet på heapen
}
// Car-objektet på heapen lever kvar tills GC städar

Hur GC vet vad den kan ta bort

GC letar efter rötter — aktiva variabler, statiska fält och anrop på call-stacken. Allt som kan nås från en rot är “levande”. Allt som inte kan nås är skräp och kan tas bort.

var a = new Car("Volvo"); // a pekar på ett Car-objekt
var b = a; // b pekar på samma objekt
a = null; // a pekar inte längre dit
// men b gör det — objektet lever kvar
b = null; // nu pekar ingen dit — kan städas av GC

Generationer

.NETs GC delar in heapen i tre generationer för att jobba effektivt:

GenerationInnehållerStädas
Gen 0Nyskapade objektOfta — snabbt
Gen 1Objekt som överlevde Gen 0Ibland
Gen 2Långlivade objektSällan — långsamt

Kortlivade objekt (t.ex. temporära variabler i loopar) städas snabbt från Gen 0. Det gör att GC inte behöver gå igenom hela heapen varje gång.

Du behöver sällan tänka på GC

I de allra flesta C#-program behöver du inte tänka på minne alls. GC sköter det.

Undantag — när du håller ohanterade resurser (filer, databasanslutningar, nätverksanslutningar) behöver du hjälpa till med IDisposable:

using var file = File.OpenRead("data.txt"); // stängs automatiskt

Se Destruktor och Finalizer för detaljer.

Manuellt anropa GC (gör inte detta i produktion)

Du kan be GC att köra, men det är nästan aldrig rätt väg:

GC.Collect(); // trigga GC — undvik i riktig kod
GC.WaitForPendingFinalizers(); // vänta på finalizerkön

Manuella GC-anrop kan faktiskt göra saker långsammare eftersom du avbryter GC:ns optimerade schema.

Minnesläckor i C#

Trots GC kan du orsaka minnesläckor i C# — vanligast när:

  • Du prenumererar på events men aldrig avprenumererar (+= utan -=)
  • Du håller statiska listor som fortsätter växa
  • Du lägger till objekt i cacher utan att ta bort dem
// Klassisk event-läcka
knapp.Click += HandleClick; // prenumeration
// Om du aldrig skriver: knapp.Click -= HandleClick;
// ... lever objektet kvar så länge knappen finns

TL;DR

  • GC frigör minne automatiskt — du behöver nästan aldrig tänka på det
  • Objekt på heapen lever tills inget refererar till dem
  • Tre generationer (0, 1, 2) gör GC effektiv för kortlivade objekt
  • Ohanterade resurser (filer, anslutningar) hanteras med IDisposable + using
  • Undvik GC.Collect() — lita på GC:ns eget schema