Episode ini membedah arsitektur CRuby: alur dari source code ke Prism parser, bytecode, YARV VM, peran Garbage Collection dan GVL, dua JIT (YJIT dan ZJIT), model everything is object, serta distribusi Ruby seperti CRuby, JRuby, dan TruffleRuby.

Ketika kalian menjalankan ruby halo.rb, apa yang sebenarnya terjadi di balik layar? Ruby modern bukan lagi interpreter yang membaca baris demi baris secara naif. Ada sebuah pipeline yang matang: parsing, kompilasi ke bytecode, eksekusi oleh mesin virtual, plus manajemen memori otomatis. Memahami pipeline ini akan mengubah cara kalian menulis dan mengoptimasi kode Ruby.
Episode 2 ini membedah arsitektur CRuby (juga disebut MRI, Matz's Ruby Interpreter): alur eksekusi dari source code sampai hasil, peran Prism parser dan YARV VM, Garbage Collection, kunci global GVL, serta dua JIT modern — YJIT untuk produksi dan ZJIT yang eksperimental. Kalian juga akan memahami model objek everything is object yang menjadi jantung filosofi Ruby, dan beragam distribusi Ruby yang tersedia.
CRuby tidak mengeksekusi teks sumber langsung. Ada kompilasi internal yang menghasilkan bytecode untuk mesin virtual. Parser default sejak Ruby 3.4 adalah Prism — parser cepat dan portable yang menggantikan parser lama. Urutannya:
source code -> Prism parser -> AST -> bytecode -> YARV VM -> eksekusiUntuk melihat bytecode yang dihasilkan, Ruby menyediakan flag inspeksi bawaan:
ruby --dump=insns -e 'puts 1 + 2'Command ruby --dump=insns menampilkan instruction sequence YARV — kalian akan melihat instruksi seperti putobject, opt_plus, dan opt_send_without_block. Ini membuktikan bahwa Ruby memang mengompilasi source code menjadi bytecode sebelum dieksekusi, bukan membaca teks per baris.
YARV (Yet Another Ruby VM) adalah stack-based virtual machine yang mengeksekusi bytecode tersebut. Karena bahasa ini dinamis, setiap nilai direpresentasikan sebagai object yang dialokasikan di heap, dan dibersihkan secara otomatis oleh GC (Garbage Collection) ketika tidak lagi dirujuk. Kalian tidak perlu mengelola memori secara manual — fokus menulis logika, dan GC yang menangani pembersihan.
Konsekuensinya, allocation object sangat sering terjadi. Itulah mengapa episode 17 nanti akan membahas cara meminimalkan allocation untuk performa, misalnya dengan memakai loop daripada alokasi objek per iterasi.
Satu hal yang perlu dicatat: bytecode yang dihasilkan Prism bersifat portable dan bisa di-dump ke file, tetapi dalam praktik sehari-hari kalian tidak perlu menyentuhnya. Pemahaman konseptual tentang pipeline ini sudah cukup untuk membuat keputusan yang tepat, misalnya mengapa kode dalam bentuk loop jauh lebih cepat daripada pembentukan objek baru setiap iterasi.
GVL (Global VM Lock) memastikan hanya satu thread Ruby yang menjalankan bytecode dalam satu waktu. Ini menjamin keamanan memori internal, tetapi membatasi paralelisme CPU untuk workload berat. Untuk menembus batas ini, Ruby menyediakan Ractor — subjek episode 11 — yang berjalan paralel sejati di luar GVL. Pahami dulu: thread Ruby itu concurrent untuk I/O, tetapi tidak parallel untuk CPU.
Dua JIT (Just-In-Time compiler) hadir untuk mempercepat eksekusi kode panas (hot code). Perbedaan utama keduanya ada pada strategi kompilasi dan kematangan fiturnya. Untuk Ruby 4.0, kedua JIT bisa diaktifkan berdampingan melalui flag command line yang terpisah, sehingga kalian bisa membandingkan mana yang lebih cepat untuk workload kalian:
--yjit.--zjit.ruby --yjit -e 'puts "YJIT aktif, direkomendasikan untuk produksi"'
ruby --zjit -e 'puts "ZJIT aktif, masih eksperimental"'Untuk workload production, rekomendasi kami tetap YJIT. Command ruby --yjit dan ruby --zjit bisa juga dipasang permanen melalui environment variable RUBYOPT. Detail pengukuran performa kedua JIT ini ada di episode 17 dan 21.
Di Ruby, setiap nilai adalah objek — termasuk angka, string, bahkan nil. Setiap objek memiliki kelas, dan method dipanggil dengan mengirim pesan ke objek tersebut. Inilah mengapa Ruby disebut bahasa berorientasi objek murni, tanpa primitif yang "bukan objek":
puts 42.class
puts "halo".class
puts 3.14.methods.count
puts nil.classOutput dari block kode di atas menampilkan Integer, String, Float, dan NilClass. Bahkan nil adalah objek dari kelas NilClass. Ekspresi 42.class menunjukkan cara menanyakan kelas sebuah nilai, dan 3.14.methods.count membuktikan bahwa nilai numerik pun memiliki ratusan method.
Kelas dan modul itu sendiri adalah objek. Ketika sebuah objek dibuat, Ruby memberinya singleton class pribadi di balik layar yang memungkinkan method didefinisikan khusus untuk objek tersebut. Rantai pencarian method berjalan dari singleton class, naik ke kelas, kemudian modul yang di-include, dan seterusnya hingga BasicObject. Mekanisme ini menjadi fondasi metaprogramming di episode 19, jadi pahami arah pencariannya sejak sekarang.
Karena kelas adalah objek, kalian bisa bertanya soal kelas seperti bertanya pada objek biasa:
puts String.class
puts String.superclass
puts "teks".is_a?(Object)Outputnya menampilkan Class (kelas dari String adalah objek Class), Object (superclass dari String), dan true. Ekspresi "teks".is_a?(Object) memakai method is_a? untuk mengecek hubungan pewarisan. Konsep ini nanti sangat membantu saat membaca kode framework seperti Rails yang banyak membuka dan memodifikasi kelas.
Ruby yang kita install lewat rbenv adalah CRuby — implementasi referensi resmi yang dikelola Ruby core team. Tapi ada implementasi lain dengan kelebihan masing-masing:
Untuk membedakan implementasi yang sedang berjalan, Ruby menyediakan konstanta bawaan:
ruby -e 'puts RUBY_ENGINE'
rbenv versionsCommand ruby -e 'puts RUBY_ENGINE' menampilkan ruby untuk CRuby, jruby untuk JRuby, dan truffleruby untuk TruffleRuby. Sementara rbenv versions menampilkan semua versi Ruby yang terinstall. Keputusan memilih JRuby atau TruffleRuby untuk produksi akan dibahas di episode 22.
Info
Seluruh series ini memakai CRuby. Ketika materi menyebut versi seperti 4.0.6 atau 3.4.10, yang dimaksud adalah versi CRuby resmi dari ruby-lang.org.
Episode 2 membuka tabir arsitektur Ruby: pipeline dari source code melewati Prism parser dan YARV VM, manajemen memori oleh GC, batasan GVL untuk thread, dua JIT (YJIT untuk produksi, ZJIT eksperimental), model everything is object, serta peta distribusi CRuby, JRuby, dan TruffleRuby.
Inti yang harus dibawa pulang:
RUBY_ENGINE membedakan CRuby, JRuby, dan TruffleRuby.Di episode 3 selanjutnya kita akan membahas sintaks dasar dan tipe data — variabel dan konstanta beserta aturan penamaannya, tipe Integer, Float, String, Symbol, Array, Hash, dan Range, komentar, output dengan p dan puts, string interpolation, serta perbedaan simbol dan string. Di sinilah kalian mulai benar-benar menulis Ruby.