Graydon Hoare dan Rust: Pergeseran Sistem yang Aman Secara Memori
Dari eksperimen Graydon Hoare 2006 sampai ekosistem Rust hari ini — lihat bagaimana keamanan memori tanpa garbage collector membentuk ulang pemrograman sistem.

Apa yang Dijelaskan Cerita Ini (dan Apa yang Tidak)
Artikel ini menceritakan sebuah origin story yang fokus: bagaimana eksperimen pribadi Graydon Hoare berkembang menjadi Rust, dan mengapa pilihan desain Rust cukup penting untuk mengubah ekspektasi terhadap pemrograman sistem.
Apa yang kami maksud dengan “systems programming”
“Systems programming” berada dekat dengan mesin—dan dekat dengan risiko produk Anda. Ia muncul di peramban, mesin game, komponen sistem operasi, basis data, jaringan, dan perangkat lunak embedded—tempat-tempat di mana biasanya Anda memerlukan:
- Kinerja tinggi (pekerjaan harus cepat dan dapat diprediksi)
- Kontrol tingkat-rendah (alokasi memori, threading, tata letak data)
- Keandalan (crash dan bug keamanan mahal)
Secara historis, kombinasi itu mendorong tim ke C dan C++, plus aturan, review, dan tooling ekstensif untuk mengurangi bug terkait memori.
Janji inti yang akan kita uraikan
Janji headline Rust mudah diucapkan dan sulit diwujudkan:
Keamanan memori tanpa garbage collector.
Rust bertujuan mencegah kegagalan umum seperti use-after-free, double-free, dan banyak jenis race—tanpa mengandalkan runtime yang secara periodik menghentikan program untuk mengambil kembali memori. Sebagai gantinya, Rust memindahkan banyak pekerjaan itu ke waktu kompilasi melalui ownership dan borrowing.
Lingkup—apa yang termasuk dan apa yang tidak
Anda akan mendapatkan sejarah (dari gagasan awal sampai keterlibatan Mozilla) dan konsep kunci (ownership, borrowing, lifetimes, safe vs. unsafe) dijelaskan dalam bahasa sederhana.
Yang tidak Anda dapatkan adalah tutorial Rust lengkap, tur sintaksis penuh, atau panduan langkah-demi-langkah setup proyek. Anggap ini sebagai “mengapa” di balik desain Rust, dengan contoh singkat untuk membuat idenya konkret.
Catatan penulis: versi penuh menargetkan ~3.000 kata, memberi ruang untuk contoh singkat tanpa berubah menjadi manual referensi.
Eksperimen Awal Graydon Hoare yang Menjadi Rust
Rust tidak dimulai sebagai bahasa "pemenang" yang dirancang oleh komite. Ia bermula dari eksperimen pribadi Graydon Hoare pada 2006—pekerjaan yang ia kejar secara independen sebelum menarik perhatian lebih luas. Asal-usul itu penting: banyak keputusan desain awal tampak seperti upaya menyelesaikan rasa sakit sehari-hari, bukan untuk “menang” dalam teori bahasa.
Motivasi awal: kekuatan tingkat-rendah, lebih sedikit jebakan
Hoare mengeksplorasi cara menulis perangkat lunak tingkat-rendah dan berkinerja tinggi tanpa mengandalkan garbage collection—sambil menghindari penyebab crash dan bug keamanan paling umum di C dan C++. Ketegangan ini akrab bagi pemrogram sistem:
- Anda ingin kontrol langsung atas memori dan tata letak untuk kecepatan.
- Anda ingin keselamatan praktis agar kesalahan tidak diam-diam menjadi kerentanan.
- Anda ingin konkruensi yang bisa digunakan, karena kinerja modern sering berarti banyak thread.
Arah “keamanan memori tanpa GC” Rust bukan awalnya slogan pemasaran. Itu adalah target desain: pertahankan karakteristik kinerja yang sesuai untuk kerja sistem, tetapi buat banyak kategori bug memori sulit untuk diekspresikan.
Mengapa harus bahasa baru (bukan hanya alat yang lebih baik)
Wajar bertanya kenapa ini bukan "hanya kompiler yang lebih baik" untuk C/C++. Alat seperti analisis statis, sanitizer, dan library yang lebih aman mencegah banyak masalah, tetapi umumnya tidak bisa menjamin keamanan memori. Bahasa dasar mengizinkan pola yang sulit—atau tidak mungkin—diawasi sepenuhnya dari luar.
Taruhan Rust adalah memindahkan aturan kunci ke dalam bahasa dan sistem tipenya sehingga keselamatan menjadi hasil default, sambil tetap mengizinkan kontrol manual dalam jalur-jalur pelolosan yang jelas ditandai.
Menjaga cerita tetap berlandas: fakta vs. lore
Beberapa detail tentang hari-hari awal Rust beredar sebagai anekdot (sering diulang dalam presentasi dan wawancara). Saat menceritakan origin story ini, membantu memisahkan tonggak yang didokumentasikan luas—seperti dimulainya pada 2006 dan adopsi Rust di Mozilla Research—dari kenangan pribadi dan penceritaan sekunder.
Untuk sumber primer, cari dokumentasi desain Rust awal, catatan desain, pembicaraan/wawancara Graydon Hoare, dan posting era Mozilla/Servo yang menjelaskan mengapa proyek diadopsi dan bagaimana tujuannya dibingkai. Bagian “baca lebih lanjut” yang solid bisa mengarahkan pembaca ke dokumen-dokumen asli (lihat /blog untuk tautan terkait).
Masalah Pemrograman Sistem: Kode Cepat, Memori Rapuh
Pemrograman sistem sering berarti bekerja dekat perangkat keras. Kedekatan itu membuat kode cepat dan efisien sumber daya. Tapi itu juga membuat kesalahan memori sangat menghukum.
Penjahat biasanya: bug memori
Beberapa bug klasik muncul berulang kali:
- Use-after-free: program terus menggunakan memori setelah dilepaskan, seperti menulis di buku catatan yang sudah Anda buang.\n- Double free: memori dibebaskan dua kali, membingungkan allocator dan kadang membuka celah eksploitasi.\n- Buffer overflow: data meluap melewati akhir wilayah yang dialokasikan, berpotensi merusak data atau alur kontrol di sekitarnya.
Kesalahan-kesalahan ini tidak selalu jelas. Program bisa “berjalan” selama berminggu-minggu, lalu crash hanya di bawah pola input atau timing yang jarang.
Mengapa testing tidak menyelamatkan Anda
Testing membuktikan sesuatu bekerja untuk kasus yang Anda uji. Bug memori sering bersembunyi di kasus yang Anda tidak uji: input yang tidak biasa, perangkat keras berbeda, perubahan kecil pada timing, atau versi kompiler baru. Mereka juga bisa non-deterministik—terutama pada program multi-threaded—sehingga bug menghilang saat Anda menambahkan logging atau memasang debugger.
Biaya nyata: keamanan, stabilitas, waktu
Ketika memori salah, Anda tidak hanya mendapatkan error yang bersih. Anda mendapatkan status yang korup, crash yang tak terduga, dan kerentanan keamanan yang aktif dicari penyerang. Tim menghabiskan usaha besar mengejar kegagalan yang sulit direproduksi dan bahkan lebih sulit didiagnosis.
Kecepatan vs keselamatan: ketegangan inti
Perangkat lunak tingkat-rendah tidak selalu bisa “membayar” untuk keselamatan dengan pemeriksaan runtime berat atau pemindaian memori terus-menerus. Tujuannya lebih mirip meminjam alat dari bengkel bersama: Anda dapat menggunakannya bebas, tetapi aturannya harus jelas—siapa yang memegangnya, siapa yang boleh berbagi, dan kapan harus dikembalikan. Bahasa tradisional untuk sistem menyerahkan aturan-aturan itu pada disiplin manusia. Cerita asal Rust dimulai dengan mempertanyakan tradeoff itu.
Mengapa “Keamanan Memori Tanpa GC” Itu Penting
Garbage collection adalah cara umum bahasa mencegah bug memori. Alih-alih memaksa Anda membebaskan memori, runtime melacak objek yang masih dapat dijangkau dan otomatis mereklamasi sisanya. Itu menghilangkan kategori masalah—use-after-free, double free, dan banyak kebocoran—karena program tidak bisa “lupa” membersihkan dengan cara yang sama.
Trade-off GC dalam kode bergaya sistem
GC tidaklah “buruk,” tetapi mengubah profil kinerja program. Sebagian besar kolektor memperkenalkan kombinasi:
- Waktu jeda (meskipun kecil atau inkremental), yang bisa muncul sebagai jeda/lag\n- Overhead runtime untuk melacak alokasi dan keterjangkauan\n- Latensi yang kurang dapat diprediksi, karena kerja koleksi terjadi saat runtime memutuskan
Untuk banyak aplikasi—backend web, perangkat lunak bisnis, tooling—biaya itu dapat diterima atau bahkan tak terlihat. GC modern sangat baik dan meningkatkan produktivitas pengembang secara dramatis.
Di mana prediktabilitas penting
Dalam pemrograman sistem, kasus terburuk sering paling penting. Mesin peramban memerlukan rendering yang mulus; pengendali embedded mungkin punya batas waktu ketat; server latency-rendah dioptimalkan untuk menjaga tail latency tetap ketat di bawah beban. Di lingkungan ini, “biasanya cepat” kurang bernilai daripada “konsisten dapat diprediksi.”
Pitch Rust: keselamatan dengan kontrol
Janji besar Rust: pertahankan kontrol seperti C/C++ atas memori dan tata letak data, tetapi berikan keamanan memori tanpa mengandalkan garbage collector. Tujuannya karakteristik kinerja yang dapat diprediksi—sambil membuat kode yang aman menjadi default.
Ini bukan argumen bahwa GC inferior. Ini taruhan bahwa ada ruang tengah penting: perangkat lunak yang membutuhkan kontrol tingkat-rendah dan jaminan keselamatan modern.
Ownership: Gagasan Inti di Balik Keselamatan Rust
Ownership adalah ide besar paling sederhana Rust: setiap nilai memiliki satu pemilik yang bertanggung jawab membersihkannya ketika tidak lagi diperlukan.
Aturan tunggal itu menggantikan banyak pembukuan manual "siapa yang membebaskan ini?" yang sering diingat pemrogram C/C++ di kepala mereka. Alih-alih mengandalkan disiplin, Rust membuat pembersihan dapat diprediksi.
Move vs Copy (dengan kata-kata sederhana)
Saat Anda copy sesuatu, Anda berakhir dengan dua versi independen. Saat Anda move sesuatu, Anda menyerahkan yang asli—setelah move, variabel lama tidak lagi boleh menggunakannya.
Rust memperlakukan banyak nilai yang dialokasikan di heap (seperti string, buffer, atau vector) sebagai moved secara default. Menyalinnya seenaknya bisa mahal dan, lebih penting, membingungkan: jika dua variabel mengira mereka “pemilik” dari alokasi yang sama, Anda menyiapkan panggung untuk bug memori.
Berikut ide singkat dalam pseudo-code kecil:
buffer = make_buffer()
ownerA = buffer // ownerA owns it
ownerB = ownerA // move ownership to ownerB
use(ownerA) // not allowed: ownerA no longer owns anything
use(ownerB) // ok
// when ownerB ends, buffer is cleaned up automatically
(Blok kode di atas tidak diubah.)
Imbalan: pembersihan tanpa garbage collector
Karena selalu ada tepat satu owner, Rust tahu persis kapan sebuah nilai harus dibersihkan: ketika pemiliknya keluar dari scope. Itu berarti manajemen memori otomatis (Anda tidak memanggil free() di mana-mana) tanpa perlu garbage collector yang memindai program saat runtime.
Apa yang dicegah dalam praktik
Aturan ownership ini memblokir kelas besar masalah klasik:
- Double-free: dua “pemilik” mencoba membebaskan memori yang sama.\n- Use-after-free: kode terus menggunakan pointer setelah memori sudah dilepaskan.
Model ownership Rust tidak hanya mendorong kebiasaan yang lebih aman—ia membuat banyak keadaan yang tidak aman tidak dapat direpresentasikan, yang menjadi fondasi fitur keselamatan Rust lainnya.
Borrowing, Lifetimes, dan Borrow Checker
Ownership menjelaskan siapa “pemilik” sebuah nilai. Borrowing menjelaskan bagaimana bagian lain program dapat sementara menggunakan nilai itu tanpa mengambilnya.
Borrowing: akses tanpa ownership
Saat Anda meminjam sesuatu di Rust, Anda mendapatkan referensi ke situ. Pemilik asli tetap bertanggung jawab membersihkan memori; peminjam hanya mendapat izin untuk menggunakannya untuk sementara.
Rust memiliki dua jenis borrow:
- Shared borrow (
&T): akses baca-saja. - Mutable borrow (
&mut T): akses baca-tulis.
Aturan kunci: banyak pembaca atau satu penulis
Aturan pinjam pusat Rust mudah diucapkan dan kuat dalam praktik:
- Anda bisa memiliki banyak referensi bersama ke sebuah nilai pada waktu yang sama, atau\n- Anda bisa memiliki satu referensi mutable,\n- Tetapi tidak keduanya sekaligus.
Aturan ini mencegah kelas bug umum: satu bagian program membaca data sementara bagian lain mengubahnya di bawahnya.
Lifetimes: “berapa lama referensi ini valid?”
Sebuah referensi hanya aman jika tidak pernah bertahan lebih lama daripada hal yang ditunjuknya. Rust menyebut durasi itu lifetime—jangka waktu di mana referensi dijamin valid.
Anda tidak perlu formalisme untuk memakai ide ini: sebuah referensi tidak boleh tetap ada setelah pemiliknya hilang.
Borrow checker: keselamatan sebelum program dijalankan
Rust menegakkan aturan ini saat kompilasi melalui borrow checker. Alih-alih berharap testing menangkap referensi yang buruk atau mutasi berisiko, Rust menolak membangun kode yang dapat menggunakan memori dengan cara yang salah.
Contoh yang dapat dibandingkan
Bayangkan dokumen bersama:
- Jika beberapa orang melihatnya, itu seperti shared borrows: aman, karena tidak ada yang mengubah teks.\n- Jika satu orang mengedit, itu seperti mutable borrow: aman, karena ada satu sumber kebenaran.\n- Membiarkan seseorang mengedit sementara orang lain membaca berisiko membuat pembaca melihat perubahan yang setengah selesai—Rust mencegah situasi itu dengan desain.
Pertanyaan umum
Apa arti “systems programming” dalam artikel ini?
Pemrograman sistem adalah pekerjaan yang berada dekat perangkat keras dan permukaan risiko produk—seperti mesin peramban, basis data, komponen OS, jaringan, dan perangkat embedded.
Biasanya menuntut kinerja yang dapat diprediksi, kontrol memori/tingkat-rendah, dan keandalan tinggi, di mana crash dan bug keamanan bisa sangat mahal.
Apa arti sebenarnya dari “memory safety without a garbage collector”?
Artinya Rust berusaha mencegah bug memori umum (seperti use-after-free dan double-free) tanpa bergantung pada garbage collector (GC).
Alih-alih runtime yang memindai dan mereklamasi memori saat program berjalan, Rust memindahkan banyak pengecekan keselamatan ke waktu kompilasi melalui aturan ownership dan borrowing.
Mengapa Rust harus menjadi bahasa baru, bukan “alat yang lebih baik untuk C/C++”?
Sanitizer dan analisis statis bisa menemukan banyak masalah, tapi biasanya mereka tidak bisa menjamin keselamatan memori jika bahasa itu sendiri membolehkan pola pointer dan lifetime yang berbahaya.
Rust memasukkan aturan kunci ke dalam bahasa dan sistem tipe sehingga kompiler bisa menolak kategori bug tertentu secara bawaan, sambil tetap menyediakan jalur keluar eksplisit saat perlu.
Mengapa garbage collection tidak selalu dapat diterima untuk kode sistem?
GC bisa menambah overhead runtime dan, yang lebih penting untuk beberapa beban kerja sistem, menghasilkan latensi yang kurang dapat diprediksi (mis. jeda atau kerja koleksi pada waktu yang tidak diinginkan).
Di domain seperti peramban, pengendali waktu-nyata, atau layanan latency-rendah, perilaku kasus terburuk penting—jadi Rust menargetkan keselamatan sambil mempertahankan karakteristik kinerja yang lebih dapat diprediksi.
Apa itu ownership di Rust, dengan bahasa yang sederhana?
Ownership berarti setiap nilai memiliki satu “penanggung jawab” (owner). Ketika owner keluar dari scope, nilai itu dibersihkan secara otomatis.
Ini membuat pembersihan menjadi dapat diprediksi dan mencegah situasi di mana dua tempat mengira mereka harus membebaskan alokasi yang sama.
Apa perbedaan antara moving dan copying di Rust, dan mengapa itu penting?
Sebuah move mentransfer ownership dari satu variabel ke variabel lain; variabel asal tidak bisa lagi menggunakan nilai tersebut setelah dipindahkan.
Ini mencegah "dua pemilik" untuk satu alokasi, yang sering menjadi akar penyebab double-free dan use-after-free pada bahasa dengan manajemen memori manual.
Bagaimana borrowing dan aturan “many readers or one writer” bekerja?
Borrowing memungkinkan kode menggunakan sebuah nilai sementara melalui referensi tanpa mengambil ownership.
Aturan inti: banyak pembaca atau satu penulis—kamu bisa punya banyak referensi bersama (&T) atau satu referensi mutable (&mut T), tetapi tidak keduanya sekaligus. Ini mencegah banyak bug kelas mutation-while-reading dan aliasing.
Apa itu lifetimes, dan apa yang ditegakkan oleh borrow checker?
Lifetime adalah “berapa lama sebuah referensi valid.” Rust mengharuskan referensi tidak pernah bertahan lebih lama daripada data yang ditunjuknya.
Borrow checker menegakkan ini saat kompilasi, sehingga kode yang dapat menghasilkan referensi menggantung (dangling) ditolak sebelum dijalankan.
Bagaimana Rust membantu mencegah data race pada kode konkuren?
Data race terjadi ketika beberapa thread mengakses memori yang sama secara bersamaan, setidaknya satu akses adalah write, dan tidak ada koordinasi.
Aturan ownership/borrowing Rust meluas ke konteks konkruensi sehingga pola sharing berbahaya sulit atau tidak mungkin diekspresikan dalam kode aman (safe). Itu mendorong penggunaan primitif sinkronisasi atau message passing yang eksplisit.
Apa perbedaan antara safe Rust dan unsafe Rust, dan kapan menggunakan `unsafe`?
Sebagian besar kode ditulis dalam safe Rust, di mana kompiler menegakkan aturan keselamatan memori.
unsafe adalah jalur keluar yang jelas untuk operasi yang kompiler tidak bisa buktikan aman secara umum (mis. panggilan FFI atau primitif tingkat-rendah). Praktik umum: simpan unsafe kecil dan bungkus dengan API yang aman sehingga bagian yang berisiko mudah diaudit.