Objek di managed heap tidak dibebaskan pada saat tertentu yang bisa kita tentukan; usianya mengikuti rujukan yang masih terpakai. Selama ada satu variabel, field, atau elemen koleksi yang masih menunjuk objek, GC membiarkan objek tersebut tetap ada. Begitu seluruh rujukan hilang, objek menjadi kandidat pengklaiman pada siklus GC berikutnya. Konsep ini disebut reference lifetime, dan kita akan membuktikannya dengan WeakReference, yaitu rujukan khusus yang tidak menahan objek.
Contoh: Dua Fase Usia Objek #
TunjukkanSelamatSaatDirujuk();
TunjukkanDiklaimTanpaRujukan();
void TunjukkanSelamatSaatDirujuk()
{
byte[] kunci = new byte[1_000];
var jejak = new WeakReference(kunci);
GC.Collect();
Console.WriteLine($"Selama dirujuk : {jejak.IsAlive}");
GC.KeepAlive(kunci);
}
void TunjukkanDiklaimTanpaRujukan()
{
var jejak = BuatJejak();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine($"Setelah dilepas: {jejak.IsAlive}");
}
WeakReference BuatJejak()
{
byte[] kunci = new byte[1_000];
return new WeakReference(kunci);
}Output yang Dihasilkan:
Selama dirujuk : True
Setelah dilepas: FalseMari kita bedah baris demi baris:
new WeakReference(kunci): kita menyimpan rujukan lemah ke array. Rujukan lemah tidak menjaga objek tetap ada, tetapi masih bisa mengintip kondisinya.GC.Collect()pada fase pertama: GC berjalan, tetapi variabelkuncimasih menunjuk array, sehingga array lolos danIsAlivebernilaiTrue. PemanggilanGC.KeepAlive(kunci)memastikan compiler tidak menganggap variabel tersebut selesai lebih awal.BuatJejak()pada fase kedua: array dibuat di dalam method terpisah. Ketika method tersebut kembali, tidak ada lagi rujukan kuat yang tersisa ke array.GC.Collect()pada fase kedua: GC tidak menemukan rujukan kuat, sehingga array diklaim kembali danIsAliveberubah menjadiFalse.
Rujukan yang Tidak Sengaja Dipertahankan #
Kebocoran memori di aplikasi .NET jarang berupa objek yang tak terdeteksi; objeknya justru masih dirujuk, hanya saja tanpa disadari. Penyebab yang paling sering: event yang berlangganan tetapi tidak dilepas, field static yang terus memegang data lama, dan closure yang menangkap variabel besar. Bab Event Memory Leaks pada section Delegates dan Events membahas kasus event secara khusus.