Tipe Nilai dan Tipe Referensi

Tipe item data menentukan dua hal: ukuran memori (jumlah bit) yang dibutuhkan untuk menyimpannya, serta anggota data yang dimiliki tipe tersebut. Selain itu, tipe juga mengatur lokasi penempatan objek di memori, yaitu di Stack (Tumpukan) atau Heap (Tumpukan Besar).

Tipe dibagi menjadi dua kelompok utama: Tipe Nilai (Value Types) dan Tipe Referensi (Reference Types). Cara penyimpanan dua jenis objek ini di memori sangat berbeda satu sama lain.

1. Tipe nilai hanya menggunakan satu blok memori, blok ini langsung menyimpan data asli tanpa perantara.

Data tipe nilai disimpan langsung di Stack, bagian Data menampung nilai asli. Contohnya int age = 12; angka 12 akan langsung tersimpan di stack tersebut

2. Tipe referensi memerlukan dua bagian memori terpisah:

  • Bagian pertama menampung data asli objek dan bagian ini selalu dialokasikan di Heap;
  • Bagian kedua adalah alamat referensi yang menunjuk posisi data di heap. (Stack hanya menyimpan alamat heap, pada masa bahasa C bagian ini disebut pointer atau penunjuk)
Data utama tipe referensi ada di heap dan diberi alamat unik seperti 000001, lalu stack akan menyimpan alamat referensi tersebut bernama Reference

Dua gambar di atas hanya berlaku jika objek tidak menjadi anggota data dari objek lain.

Catatan Penting

Bagian data utama objek tipe referensi akan selalu ditempatkan di heap, sesuai gambar di atas.

Namun instansi tipe nilai atau alamat referensi tipe referensi bisa berada di stack maupun heap, tergantung bagaimana kode ditulis.

Contoh:

Misalkan ada tipe referensi Person yang memiliki dua anggota: satu anggota tipe nilai dan satu anggota tipe referensi.

Banyak orang salah paham dan mengira anggota tipe nilai ada di stack, alamat referensi juga di stack, sedangkan data utama objek ada di heap (seperti gambar di atas), namun pemikiran ini salah.

Ingat satu aturan: Semua data utama instansi tipe referensi akan selalu dialokasikan di heap. Kedua anggota termasuk dalam data utama objek ini, jadi baik tipe nilai maupun tipe referensi semuanya akan disimpan bersama di heap.

Contoh kode:

class Program
{
    static void Main(string[] args)
    {
        int a = 10;
        Person bill = new Person("Bill", 18);
    }

}

class Person
{
    private string name;

    private int age;

    private Phone myPhone;

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
        this.myPhone = new Phone();
        this.myPhone.number = 12345;
    }
}   

class Phone
{
    public long number;
}Code language: JavaScript (javascript)

Lihat contoh di atas, kelas Person memiliki tipe bawaan age dan name, serta tipe buatan sendiri bernama Phone. Tipe Phone sendiri memiliki tipe bawaan long untuk menyimpan nomor telepon genggam.

Pembaca mungkin melihat int age di dalam Person atau long number di dalam Phone lalu mengira keduanya tipe nilai sehingga tersimpan di stack, padahal tidak. Meskipun keduanya tipe dasar bawaan, karena menjadi anggota dari tipe kelas buatan, mereka akan ikut tersimpan di heap bersama instansi objek. Susunan penyimpanan akhirnya akan seperti ini:

Dari gambar terlihat int age dan long number adalah tipe nilai bawaan, namun sebagai anggota tipe buatan maka disimpan di heap. Variabel myPhone menyimpan alamat referensi, jadi bagian referensi tipe referensi juga bisa tersimpan di heap.

Pelajari hal ini: Semua anggota data tipe buatan akan tersimpan di heap, tanpa peduli apakah tipe nilai atau tipe referensi. Jika ada anggota tipe referensi di dalam kelas seperti myPhone pada contoh, variabel tersebut hanya menampung alamat objek lain yang ada di heap.

Jika di dalam tipe Phone ada tipe buatan lain, maka bagian memori Phone akan memiliki ruang tambahan untuk menyimpan alamat referensi tipe buatan tersebut.

Program dimulai eksekusi dari fungsi Main, alamat objek referensi tingkat paling atas disimpan di stack, kemudian objek berikutnya akan saling terhubung seperti rantai di heap.

Referensi saling terhubung seperti sebuah rantai

Contoh lain

// Kelas tipe referensi
class MyType
{
    public int A;       // Anggota tipe nilai, tertanam di instansi MyType yang ada di heap
    public Person B;    // Anggota tipe referensi; penunjuk referensi disimpan di heap, data utama dialokasikan di bagian heap terpisah
}

class Person
{
    public string Name;
}

void Test()
{
    // Stack menyimpan penunjuk referensi milik myObj
    MyType myObj = new MyType(); 
    /*
    Susunan Heap:
    Objek MyType {
        A: nilai int yang tertanam langsung
        B: penunjuk referensi menuju instansi Person
    }
    Blok Heap terpisah: Person{ Name: ... }
    */

    // Variabel lokal tipe nilai, dialokasikan langsung di stack
    int localNum = 10;
}Code language: PHP (php)

Aturan di atas hanya berlaku untuk anggota data kelas, bukan fungsi di dalam kelas. Jika fungsi kelas memiliki variabel lokal atau objek referensi, variabel lokal tipe nilai dan alamat objek referensi tetap akan tersimpan di stack. Lihat kode berikut:

Lihat contoh berikut lagi:

using System.ComponentModel.DataAnnotations;

class Program
{
    static void Main(string[] args)
    {
        int a = 10;
        Person bill = new Person("Bill", 18);
        bill.Calculate();
    }

}

class Person
{
    private string name;

    private int age;

    private Phone myPhone;

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
        this.myPhone = new Phone();
        this.myPhone.number = 12345;
    }

    public int Calculate()
    {
        int one = 12;
        int two = 23;
        Phone myNewPhone = new Phone();
        return one + two;
    }
}   

class Phone
{
    public long number;
}Code language: PHP (php)

Saya menambahkan fungsi Calculate ke kelas Person pada kode ini. Di dalam fungsi terdapat variabel lokal tipe nilai dan tipe referensi yang dipanggil dari Main. Variabel ini bukan anggota kelas Person, melainkan variabel lokal milik fungsi. Untuk variabel lokal tipe nilai akan disimpan di stack, sedangkan alamat referensi tipe referensi lokal juga ada di stack.

Saat baris kode bill.Calculate(); dijalankan, susunan memori akan seperti gambar berikut

Bagian berwarna biru pada gambar adalah tempat penyimpanan variabel di dalam fungsi saat sedang berjalan.

Sekali fungsi selesai dijalankan, variabel-variabel lokal ini akan keluar dari stack dan susunan memori berubah seperti gambar berikut

Setelah fungsi Calculate selesai dan kendali kembali ke Main, semua variabel yang dibuat di dalam fungsi akan keluar dari stack dan hilang. Namun bagian data utama myNewPhone (bagian biru di gambar) tetap ada di heap. Yang keluar dari stack hanya alamat referensinya, data asli objek tidak langsung dihapus dan tetap menunggu proses pembersihan sampah GC di waktu yang tepat.

Tipe Nilai dan Tipe Referensi

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *