jump to navigation

Boxing and Unboxing (bagian 1 dari 2) 31 Maret 2008

Posted by firstyuyu in .net framework.
trackback

Boxing adalah proses membungkus value type ke dalam sebuah object di managed heap sehingga kita bisa memperlakukan value type sebagai reference type. Sementara unboxing adalah proses membongkar kembali suatu value type yang telah dilakukan proses boxing sehingga value type tersebut tidak bisa lagi diperlakukan sebagai reference type. Proses boxing dan unboxing ini mengharuskan compiler untuk menambahkan instruksi MSIL untuk melakukannya. Selain itu, proses ini juga melibatkan alokasi memori dan peng-copy-an variabel. Jika boxing dan unboxing terjadi di dalam sebuah looping yang sangat banyak, hal ini bisa menyebabkan penurunan performance aplikasi yang sangat signifikan.

Value type memang lebih ringan jika dibandingkan dengan reference type karena value type tidak dialokasikan di managed heap, tidak mempunyai overhead field (type object pointer dan sync block index), serta tidak membutuhkan garbage collector. Namun ada kalanya kita harus mengkonversi value type menjadi reference type seperti ketika kita ingin melewatkan value type ke parameter method yang meminta reference type. Salah satu contohnya adalah ketika kita ingin menyimpan value type ke dalam ArrayList seperti contoh berikut:  

struct Titik
{
    public int x, y;
}
class Program
{
    static void Main(string[] args)
    {
        ArrayList arr = new ArrayList();
        Titik t; //Alokasi titik di stack
        for (int i = 0; i < 100; i++)
        {           
            //inisialisasi nilai x dan y
            t.x = t.y = i;
            //terjadi proses boxing di sini
            arr.Add(t);
        }
    }
}

Pada kode di atas, kita deklarasikan variabel t di luar looping. Lalu setiap perulangan yang terjadi, kita inisialisasi nilai x dan y dari variabel t. Kemudian variabel t tersebut kita tambahkan ke dalam ArrayList. Mari kita merenung sejenak… Lalu apa sebenarnya yang ditaruh ke dalam ArrayList? Apakah struct Titik, alamat memori dari struct Titik, atau mungkin sesuatu yang lain?

Untuk menjawabnya, mari kita lihat deklarasi dari method Add milik class ArrayList. Deklarasinya adalah sbb:

public virtual Int32 Add(Object value);

Dari deklarasi di atas bisa kita lihat bahwa method Add meminta tipe data Object untuk parameternya, yang mengindikasikan bahwa method Add membutuhkan suatu pointer ke sebuah object yang ada di managed heap. Tapi pada source code sebelumnya saya memberikan variabel t yang merupakan value type. Agar bisa berjalan, maka variabel t tersebut harus dikonversi menjadi object yang berada di managed heap lalu alamat dari object ini akan diberikan kepada method Add tersebut. Proses inilah yang disebut sebagai boxing.

Ketika sebuah value type mengalami boxing, terjadi proses sbb:

  1. Akan terjadi alokasi memori di managed heap sebesar ukuran dari value type tersebut ditambah dengan overhead field yang ada di setiap reference type (type object pointer dan sysc block index).
  2. Semua field yang ada di value type tersebut akan di-copy-kan ke memori yang telah dialokasikan pada step nomor 1.
  3. Alamat memori yang tadi dialokasikan akan dikembalikan kepada pemanggilnya. Alamat ini merupakan referensi ke sebuah object dan value type tersebut sekarang menjadi reference type.

Compiler C# secara otomatis akan menghasilkan instruksi IL untuk melakukan proses boxing ini. Jadi dari sisi developer, proses boxing ini terjadi secara otomatis. Namun kita tetap harus memahami bagaimana sebenarnya proses boxing ini terjadi sehingga kita bisa melakukan optimasi jika terjadi isu performance yang berkaitan dengan boxing.

Pada kode di atas, compiler C# mengetahui bahwa saya memberikan value type ke sebuah method yang membutuhkan reference type, dan secara otomatis menghasilkan instruksi untuk melakukan boxing. Jadi pada saat runtime, field yang ada di variabel t akan di-copy ke memori yang dialokasikan di managed heap. Alamat dari memori yang dialokasikan di manage heap tadi akan diberikan kepada method Add. Object Titik akan tetap berada di manage heap sampai dihapus oleh garbage collector. Variabel t yang merupakan value type bisa digunakan lagi karena ArrayList tidak pernah mengetahui keberadaan variabel t. ArrayList hanya berurusan dengan nilai variabel t yang telah disalin ke managed heap. Perhatikan bahwa siklus hidup value type yang telah mengalami boxing bisa lebih panjang daripada value type pasangannya.

Catatan:

Sejak .NET framework versi 2.0, telah disertakan class collection yang berbasis pada generic. Hal ini sekaligus membuat class collection yang non-generic menjadi kadaluarsa dan sebaiknya tidak digunakan lagi. Sebagai contoh, kita sebaiknya menggunakan class System.Collection.Generic.List<T> daripada menggunakan class System.Collection.ArrayList. Class collection yang berbasis generic menawarkan banyak perbaikan dibandingkan dengan yang non-generic. Salah satu perbaikan yang paling signifikan adalah class collection yang berbasis generic memungkinkan kita untuk bekerja dengan collection yang berisi value type tanpa perlu melakukan boxing/unboxing. Hal ini tentu akan meningkatkan performa yang cukup signifikan mengingat jauh lebih sedikit object yang akan dibuat di managed heap yang juga berarti akan mengurangi proses pembersihan memori oleh garbage collector. Selain itu, dengan menggunakan collection yang berbasis generic, kita akan mendapat keuntungan lainnya yaitu compile-time type safety yang menyebabkan source code kita lebih bersih karena lebih sedikit diperlukan konversi tipe data.

__________________________________________________________________________

Setelah kita mengetahui tentang boxing, marilah sekarang kita membicarakan tentang unboxing. Misalnya kita ingin mendapatkan elemen pertama dari ArrayList dengan menggunakan kode berikut:

Titik t = arr[0];

Di sini kita mengambil pointer yang ada di element ke-0 di dalam ArrayList dan mencoba memasukkannya ke dalam variabel value type yang bertipe Titik, yaitu t. Agar bisa berjalan, maka semua field yang ada pada object Titik yang telah dilakukan proses boxing harus disalin ke dalam variabel value type t yang berada di stack. CLR melakukan mekanisme penyalinan ini dalam dua langkah. Pertama, alamat dari field yang ada pada object Titik yang telah dilakukan proses boxing diambil. Proses ini desebut unboxing. Lalu nilai dari field ini disalin dari managed heap ke variabel value type yang ada di stack.

Unboxing bukan murni proses kebalikan dari boxing. Proses unboxing jauh lebih ringan daripada proses boxing. Unboxing hanyalah proses untuk mendapatkan pointer yang menunjuk ke value type yang ada pada sebuah object hasil proses boxing. Jadi tidak seperti boxing, unboxing tidak melibatkan proses penyalinan byte di memori. Klarifikasi ini sekaligus menjelaskan banyaknya anggapan yang salah mengenai proses unboxing yang menganggap bahwa proses unboxing melibatkan penyalinan data. Namun sangat sering pada prakteknya proses boxing diikuti dengan proses penyalinan field.

Di balik layar, inilah yang sebenarnya terjadi ketika kita melakukan unboxing:

  1. Jika variabel yang menunjuk object yang telah di-box bernilai null, maka akan dimunculkan NullReferenceException.
  2. Jika variabel yang akan dilakukan unboxing tidak menunjuk ke tipe data yang benar maka akan muncul InvalidCastException.

Poin ke-dua di atas menunjukkan bahwa kode program seperti di bawah ini tidak akan bisa di-compile sebagaimana yang mungkin Anda harapkan

public static void Main()
{
    Int32 x = 5;
    Object o = x; // Terjadi boxing terhadap x
                  // o menunjuk ke object hasil
                  // boxing
    Int16 y = (Int16)o; // error InvalidCastException
}

Logikanya, seharusnya sah-sah saja untuk mengambil nilai Int32 yang telah dilakukan proses boxing yang ada ditunjuk oleh variabel o dan melakukan konversi menjadi Int16. Namun, ketika melakukan unboxing terhadap suatu object, konversi harus dilakukan ke tipe data sebenarnya dari object yang di-boxing, yaitu Int32 dalam kasus ini. Berikut ini adalah source code yang benar untuk melakukan tujuan di atas:

public static void Main()
{
    Int32 x = 5;
    Object o = x; // Terjadi boxing terhadap x
                  // o menunjuk ke object hasil
                  // boxing
    Int16 y = (Int16)(Int32)o; // unboxing ke tipe data
                               // yang tepat lalu lakukan
                               // konversi ke tipe data lainnya
}

Iklan

Komentar»

1. ridwan - 5 Januari 2017

eh kampret,,,bahasa lo udah kyk profesor doktor yang baru dapat gelar pangkat Drama Queen aja,,,biasa aja…gk smua org yg baca artikel elo org pintar semua….


Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: