Apa itu kompiler just-in-time (JIT)?
Kompiler just-in-time (JIT) adalah program yang mengubah bytecode menjadi instruksi yang dapat dikirim langsung ke prosesor (CPU) komputer. Biasanya, kompiler memainkan peran penting dalam menentukan kecepatan aplikasi bagi pengembang dan pengguna akhir. Kompiler just-in-time dapat digunakan untuk optimalisasi performa guna meningkatkan runtime aplikasi.
Berbeda dengan jenis kompiler lainnya, karakteristik utama dari kompiler JIT adalah bahwa kompiler JIT berjalan setelah suatu program dimulai dan melakukan kompilasi kode. Cara umum untuk menyebut ini adalah bahwa kompiler JIT mengkompilasi kode secara langsung atau just in time. Kode yang dikompilasi, atau urutan bytecode, diubah menjadi bahasa mesin yang lebih cepat dan lebih mudah dibaca, atau kode asli (native code). Menerjemahkan kode sumber ke dalam bahasa yang secara native dipahami oleh CPU host biasanya berarti instruksi yang lebih cepat dan lebih mudah dibaca.
Kompiler JIT berbeda dengan jenis kompiler lainnya seperti kompiler tradisional, yang mengkompilasi seluruh kode menjadi bahasa mesin sebelum program mulai berjalan. Program-program terbaru akan menggunakan kompiler JIT, yang menghasilkan kode saat program berjalan. Dua penggunaan umum kompiler JIT termasuk Java Virtual Machine (JVM) yang digunakan dalam Java, serta CLR (Common Language Runtime) yang digunakan dalam C#.
Misalnya, dalam bahasa pemrograman dan lingkungan Java, kompiler just-in-time (JIT) mengubah bytecode Java — program yang berisi instruksi yang harus diinterpretasikan — menjadi instruksi yang dapat dikirim langsung ke prosesor. Kompiler JIT sering digunakan dalam Java Runtime Environment karena digunakan untuk mengoptimalkan performa aplikasi berbasis Java.
Cara kerja kompiler just-in-time?
Bytecode adalah fitur penting dalam aplikasi yang membantu eksekusi lintas platform. Selain itu, bytecode harus dikompilasi dan diterjemahkan ke dalam bahasa yang dapat dipahami oleh CPU. Namun, cara bytecode diterjemahkan ke dalam bahasa native dapat berdampak besar pada kecepatan dan performa aplikasi. Untuk meningkatkan performa, kompiler JIT akan, saat runtime, mengkompilasi urutan bytecode yang sesuai menjadi kode mesin. Kode ini biasanya dikirim ke prosesor, di mana instruksi kode kemudian dijalankan.
Saat blok bytecode yang sama dibutuhkan kembali, kode objek yang telah dibuat sebelumnya akan digunakan. Kode yang terlihat dapat dioptimalkan kembali disebut “hot.” Kode dapat dipantau, dan jalur kode “hot” dapat dibuat untuk mengoptimalkan kode, daripada menginterpretasikan urutan kode yang sama berulang kali — yang dapat terjadi pada jenis kompiler lainnya. Dengan kemungkinan lebih kecil untuk menginterpretasikan kode berulang kali, ada lebih sedikit overhead, yang berarti kecepatan eksekusi lebih cepat. Inilah sebabnya mengapa sebagian besar implementasi JVM menggunakan kompiler JIT.
Kompiler JIT juga dapat melakukan optimasi yang relatif sederhana saat mengompilasi bytecode ke dalam bahasa mesin asli. Sebagai contoh, kompiler JIT dapat menghilangkan ekspresi sub-umum, mengurangi akses memori dalam alokasi register, serta melakukan analisis data dan operasi register dengan menerjemahkan dari operasi tumpukan.
Namun, karena waktu yang diperlukan untuk memuat dan mengompilasi bytecode, terdapat keterlambatan saat pertama kali aplikasi dijalankan. Untuk memperkirakan waktu startup, aturan praktis yang baik adalah semakin banyak kompiler JIT digunakan untuk mengoptimalkan sistem, semakin lama waktu startup awal. Ada beberapa cara untuk mengurangi keterlambatan startup awal, seperti memisahkan mode startup. Misalnya, menyertakan mode klien dan server dapat memungkinkan kompilasi dan optimasi minimal dalam satu mode dibandingkan mode lainnya, yang berarti mode yang dipilih akan memiliki waktu startup yang lebih cepat. Cara lain adalah dengan mengombinasikan kompiler JIT dengan kompiler AOT (ahead-of-time) atau interpreter.
Fase kompilasi just-in-time
Seperti yang disebutkan, kompiler JIT akan mengompilasi urutan bytecode yang sesuai menjadi kode mesin, kemudian kode tersebut dikirim ke prosesor di mana instruksi kode dijalankan.
Kompilasi JIT juga dapat dibagi berdasarkan berbagai tingkat optimasi: dingin (cold), hangat (warm), panas (hot), sangat panas (very hot), dan membara (scorching). Setiap tingkat optimasi ditetapkan untuk memberikan tingkat kinerja tertentu. Tingkat optimasi awal atau default disebut hangat (warm), sementara kode yang tampaknya dapat dioptimalkan lebih lanjut disebut panas (hot). Tingkatan ini meningkat ke atas hingga membara (scorching), di mana setiap tingkat memiliki kepentingan lebih tinggi dalam hal kinerja yang dapat dioptimalkan kembali. Melalui teknik sampling, kompiler JIT dapat menentukan metode mana yang lebih sering muncul di bagian atas tumpukan. Tingkat optimasi juga dapat diturunkan menjadi dingin (cold) untuk lebih meningkatkan waktu startup.
Kompiler just-in-time vs. interpreter vs. kompiler ahead-of-time
Pada umumnya, interpreter dan kompiler dapat digunakan untuk menerjemahkan bahasa mesin. Interpreter biasanya melakukan tugas seperti parsing, pemeriksaan tipe, dan leksing, serta melakukan pekerjaan yang sama seperti kompiler.
Interpreter memiliki waktu startup yang cepat, tidak perlu melalui langkah kompilasi, dan akan menerjemahkan kode satu baris pada satu waktu secara langsung. Namun, interpreter bisa lebih lambat dibandingkan kompiler dalam kasus di mana suatu aplikasi menjalankan kode yang sama berkali-kali, karena penerjemahan yang sama harus dilakukan sebanyak kode diulang.
Kompiler biasa tidak menerjemahkan secara langsung, karena ia menerjemahkan kode yang dikompilasi sebelum aplikasi mulai berjalan. Karena itu, waktu startupnya sedikit lebih lama, tetapi setiap loop kode yang muncul akan berjalan lebih cepat karena penerjemahan kode tidak perlu diulang berkali-kali. Kompiler juga memiliki lebih banyak waktu untuk menganalisis kode dan melakukan optimasi.
Kompiler JIT menggabungkan kedua prinsip tersebut untuk mendapatkan keunggulan dari kedua metode.
Kompiler ahead-of-time (AOT) mengompilasi kode ke dalam bahasa mesin asli seperti kompiler biasa; namun, AOT akan mengubah bytecode dari mesin virtual menjadi kode mesin.
Keuntungan kompilasi just-in-time
Keuntungan dari kompilasi JIT meliputi:
- Kompiler JIT membutuhkan lebih sedikit penggunaan memori.
- Kompiler JIT berjalan setelah program dimulai.
- Optimasi kode dapat dilakukan saat kode sedang berjalan.
- Kesalahan halaman (page faults) dapat dikurangi.
- Kode yang digunakan bersama akan dilokalkan pada halaman yang sama.
- Dapat memanfaatkan berbagai tingkat optimasi.
Kekurangan kompilasi just-in-time
Kekurangan dari kompilasi JIT meliputi:
- Waktu startup bisa memakan waktu yang cukup lama.
- Penggunaan memori cache yang tinggi.
- Menambah tingkat kompleksitas dalam program Java.
Apa yang dilakukan kompiler just-in-time dalam Java?
Dahulu, sebagian besar program yang ditulis dalam bahasa apa pun harus dikompilasi ulang, dan terkadang ditulis ulang, untuk setiap platform komputer. Salah satu keuntungan terbesar Java adalah program hanya perlu ditulis dan dikompilasi sekali. Java di platform mana pun akan menginterpretasikan bytecode yang dikompilasi menjadi instruksi yang dapat dipahami oleh prosesor tertentu.
Namun, mesin virtual menangani satu instruksi bytecode pada satu waktu. Dengan menggunakan kompiler just-in-time Java—yang sebenarnya merupakan kompiler kedua—pada platform sistem tertentu, bytecode dikompilasi menjadi kode sistem tertentu. Ini seolah-olah program telah dikompilasi sejak awal pada platform tersebut.
Setelah kode dikompilasi ulang oleh kompiler JIT, program biasanya akan berjalan lebih cepat di komputer.