Bab WeakReference di section Memory Management memperkenalkan rujukan lemah sebagai konsep; bab ini fokus pada pola pemakaiannya yang paling lazim: cache yang memberi ruang bagi GC. Ide dasarnya: simpan objek mahal di rujukan lemah, baca kembali bila masih ada, dan muat ulang bila GC telah mengklaimnya. Aplikasi tetap benar tanpa cache; cache hanya berperan sebagai penambah kecepatan yang boleh dibuang kapan saja.

Contoh: Entri Cache Berbasis WeakReference<T> #

csharp
var entriCache = BuatEntri();

TampilkanCache(entriCache);

TungguSiklusGcCache();

Console.WriteLine($"Cache setelah GC: {entriCache.TryGetTarget(out _)}");

WeakReference<LaporanBesar> BuatEntri()
{
    var laporan = new LaporanBesar(new string('*', 10_000));
    return new WeakReference<LaporanBesar>(laporan);
}

void TampilkanCache(WeakReference<LaporanBesar> entriCache)
{
    if (entriCache.TryGetTarget(out LaporanBesar laporan))
        Console.WriteLine($"Cache hangat: {laporan.Isi.Length} karakter");
}

void TungguSiklusGcCache()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
}

class LaporanBesar
{
    public LaporanBesar(string isi) => Isi = isi;

    public string Isi { get; }
}

Output yang Dihasilkan:

text
Cache hangat: 10000 karakter
Cache setelah GC: False

Mari kita bedah baris demi baris:

  1. BuatEntri(): objek LaporanBesar dibuat di dalam method dan hanya disimpan di WeakReference<LaporanBesar>, sehingga tidak ada rujukan kuat yang menahannya.
  2. entriCache.TryGetTarget(out LaporanBesar laporan): satu panggilan mengambil target sekaligus memastikan tipe data. Sebelum GC berjalan, cache melaporkan isinya, yaitu 10.000 karakter.
  3. TungguSiklusGcCache(): siklus GC eksperimen mengklaim objek yang tidak dicakup rujukan kuat.
  4. TryGetTarget(out _): hasilnya False; cache kosong dan kode pemakai harus memuat ulang data. Pada aplikasi nyata, pola “baca ulang bila kosong” inilah inti penggunaannya, dan kembaliannya sering dipasangkan dengan dictionary yang memetakan kunci ke WeakReference.

ConditionalWeakTable #

ConditionalWeakTable<TKey, TValue> menyimpan pasangan kunci-nilai di mana usia entri mengikuti usia kuncinya: begitu kunci tidak dicakup rujukan, pasangannya ikut ditinggalkan. Struktur ini lazim dipakai untuk melampirkan data tambahan pada objek milik pustaka lain tanpa mengubah class-nya, misalnya menempel metadata pada instance yang bukan milik kita. Berbeda dari WeakReference tunggal, tabel ini menjamin nilai tetap tersedia selama kuncinya tersedia, sesuatu yang tidak dapat dijanjikan WeakReference biasa.