Setiap program C# menyimpan datanya di dua area memori utama: call stack dan managed heap. Pembagian area menentukan seberapa cepat data dibuat, seberapa lama data tersedia, dan siapa yang bertugas membersihkannya. Kita perlu memahami pembagian ini sebelum menyentuh garbage collection, karena keputusan performa memori di C# selalu berangkat dari satu pertanyaan: data ini berada di stack atau di heap?
Call stack menyimpan variabel lokal dan informasi pemanggilan method; setiap method mendapat frame sendiri di stack, dan frame tersebut dibebaskan seketika saat method kembali. Managed heap jauh lebih besar dan dikelola oleh garbage collector; seluruh objek hasil operator new ditempatkan di sana.
Perbandingan Singkat #
| Aspek | Stack | Managed Heap |
|---|---|---|
| Isi utama | variabel lokal, frame method | objek hasil new |
| Kecepatan alokasi | sangat cepat, hanya geser penunjuk | cepat, tetapi ada pemeriksaan batas |
| Pembersihan | otomatis saat method kembali | oleh garbage collector |
| Ukuran | terbatas (sekitar 1 MB per thread) | mengikuti ketersediaan memori |
Contoh: Data di Stack dan di Heap #
Span<int> diStack = stackalloc int[3] { 10, 20, 30 };
int[] diHeap = new int[3] { 10, 20, 30 };
diStack[1] = 99;
diHeap[1] = 99;
Console.WriteLine($"Stack: {diStack[0]}, {diStack[1]}, {diStack[2]}");
Console.WriteLine($"Heap : {diHeap[0]}, {diHeap[1]}, {diHeap[2]}");
Console.WriteLine($"Generasi array di heap: {GC.GetGeneration(diHeap)}");Output yang Dihasilkan:
Stack: 10, 99, 30
Heap : 10, 99, 30
Generasi array di heap: 0Mari kita bedah baris demi baris:
stackalloc int[3]: runtime memesan ruang untuk tigaintlangsung di frame method yang sedang berjalan. Tidak ada objek baru di heap, sehingga tidak ada pekerjaan pembersihan di kemudian hari.new int[3]: runtime mengalokasikan array di managed heap. Array kecil (di bawah ambang 85.000 byte) mulai di generasi 0 dan menjadi tanggung jawab garbage collector.- Dua baris penugasan
diStack[1] = 99dandiHeap[1] = 99: keduanya mengubah elemen kedua. Perubahan pada stack hanya menyentuh frame method saat ini, sedangkan perubahan pada heap menyentuh objek yang bisa dibagikan ke method lain. GC.GetGeneration(diHeap): API runtime ini melaporkan generasi tempat array berada. Hasil0berarti array baru dialokasikan dan belum pernah diklaim ulang oleh GC.
Kapan Data Berpindah ke Heap #
Value type tidak otomatis berada di heap. Sebuah struct tetap di stack selama menjadi variabel lokal, tetapi berpindah ke heap saat mengalami boxing atau disimpan sebagai field class. Setiap perpindahan menciptakan pekerjaan baru bagi garbage collector.