Tekanan memori (memory pressure) menggambarkan seberapa keras aplikasi menuntut layanan GC. Dua faktor yang membentuknya: laju alokasi objek baru dan ukuran memori yang harus dipertahankan. Aplikasi dengan laju alokasi tinggi memaksa GC generasi 0 berjalan makin sering, meski jumlah objek yang tersisa kecil. Kita mulai dari mengukur tekanan yang datang dari sisi managed.
Contoh: Mengukur Alokasi Empat Buffer #
long sebelum = GC.GetAllocatedBytesForCurrentThread();
byte[] bagian1 = new byte[250_000];
byte[] bagian2 = new byte[250_000];
byte[] bagian3 = new byte[250_000];
byte[] bagian4 = new byte[250_000];
long sesudah = GC.GetAllocatedBytesForCurrentThread();
Console.WriteLine($"Empat buffer dialokasikan: {sesudah - sebelum} byte");
Console.WriteLine($"Satu buffer berukuran : {(sesudah - sebelum) / 4} byte");Output yang Dihasilkan:
Empat buffer dialokasikan: 1000096 byte
Satu buffer berukuran : 250024 byteMari kita bedah baris demi baris:
- Dua pembacaan
GC.GetAllocatedBytesForCurrentThread(): selisihnya menghitung seluruh byte yang dialokasikan thread ini di antara dua pembacaan, tanpa memandang objek itu masih dirujuk atau tidak. - Empat
new byte[250_000]: masing-masing menyumbang 250.024 byte, yaitu 250.000 byte data ditambah 24 byte overhead header objek. Totalnya 1.000.096 byte. - Makna angka: alokasi 1 MB untuk sementara bukan masalah, tetapi pola ini dalam loop yang berputar ribuan kali akan memaksa GC bekerja berkali-kali. Angka pasti dapat sedikit berbeda antar versi .NET karena ukuran header bisa berubah.
Memori Unmanaged dan GC.AddMemoryPressure #
GC hanya mengetahui managed heap. Ketika kode memakai memori unmanaged, misalnya buffer native dari P/Invoke atau pustaka gambar native, GC tidak memperhitungkannya dan bisa saja menunda pengklaiman karena heap managed tampak sepi. Dua API berikut memberi GC informasi tambahan:
GC.AddMemoryPressure(50_000_000); // beri tahu GC: ada 50 MB memori terikat
try
{
// bekerja dengan buffer native 50 MB yang masa pakainya
// terikat pada objek managed ini
}
finally
{
GC.RemoveMemoryPressure(50_000_000); // laporkan pembebasannya
}Angka yang dilaporkan tidak menambah alokasi managed; panggilan itu hanya menyesuaikan perhitungan internal GC sehingga GC memilih berjalan lebih cepat. Pasangan Add dan Remove wajib seimbang, karena selisih yang tertinggal membuat keputusan GC bias untuk selamanya.
Analisis tekanan memori dari sisi produksi (metrik, dump, dan alat CLI) dibahas pada bab Menganalisis Tekanan Memori di section Garbage Collection.