Pada bahasa dengan pengumpul sampah, strategi memori hampir tidak pernah direncanakan, karena penjadwal pembebasannya bekerja di belakang. Zig menolak lapisan itu, sehingga setiap proyek menyimpan keputusan memori yang wajib dibuat sebelum kode ditulis, bukan saat kebocoran sudah terjadi. Topik ini menyusun rencana memori dalam bentuk tabel keputusan, lalu menerjemahkannya menjadi program pelaporan yang memakai arena untuk seluruh masa hidup data sementaranya.
Konsep#
Rencana memori proyek kecil cukup dinyatakan dalam satu tabel dengan tiga kolom, yaitu jenis data, masa hidupnya, dan strateginya. Masa hidup yang sama selalu memakai strategi yang sama, dan aturan inilah yang mencegah pembukuan pembebasan tumpang tindih.
| Jenis data | Masa hidup | Strategi |
|---|---|---|
| Konfigurasi dan daftar tetap | sepanjang program | literal atau array statis |
| Data sementara per permintaan | sampai laporan selesai | ArenaAllocator tunggal |
| Struktur yang tumbuh dinamis | dikendalikan pemiliknya | GPA beserta free oleh pemilik |
| Buffer tulis ke berkas atau jaringan | sebaris pemanggilan | array stack berukuran tetap |
Empat baris tersebut mencakup hampir seluruh kebutuhan proyek skala kecil. Baris arena memusatkan seluruh pembebasan sementara pada satu deinit, baris GPA disediakan untuk struktur yang benar-benar hidup lintas permintaan, dan baris buffer stack menghindarkan alokasi tumpukan untuk kebutuhan sesaat. Rencana yang ditulis lebih dahulu membuat setiap fungsi baru hanya perlu menjawab satu pertanyaan, yaitu baris mana yang cocok untuk datanya.
Rencananya bukan dokumen yang dibekukan. Bila jenis data baru muncul dan tidak cocok dengan baris mana pun, tabelnya ditambah baris baru terlebih dahulu, bukan langsung dipenuhi kode. Perubahan baris yang sudah ada juga dicatat alasan adanya, karena strategi yang berpindah misalnya dari arena ke GPA menuntut peninjauan seluruh pemanggil fungsi yang menyalurkan datanya. Disiplin kecil ini menjaga pembukuan pembebasan tetap satu sumber kebenaran sepanjang proyek.
Ketika program berjalan sesuai rencana, jumlah panggilan pembebasan yang ditulis manual menjadi sedikit, dan pemeriksa kebocoran dari modul Memori dan allocator berfungsi sebagai verifikasi, bukan sebagai alat pencarian kebocoran berlarut-larut.
Contoh Lengkap#
Program berikut menerapkan baris arena dari tabel di atas. Laporan penjualan tiga cabang disusun ke dalam satu buffer teks, seluruh potongan teksnya berasal dari arena, dan satu panggilan arena.deinit() membebaskan semuanya.
const std = @import("std");
pub fn main() !void {
var arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
defer arena.deinit();
const alloc = arena.allocator();
const cabang = [_][]const u8{ "Gambir", "Menteng", "Cempaka" };
const penjualan = [_]u32{ 120, 85, 143 };
var laporan: std.ArrayList(u8) = .empty;
defer laporan.deinit(alloc);
var total: u32 = 0;
for (cabang, penjualan) |nama, angka| {
try laporan.print(alloc, "cabang {s}: {d} unit\n", .{ nama, angka });
total += angka;
}
try laporan.print(alloc, "total: {d} unit\n", .{total});
std.debug.print("{s}", .{laporan.items});
std.debug.print("baris laporan: {d}\n", .{cabang.len + 1});
}Dua pembebasan ditulis dalam program ini, yaitu defer laporan.deinit(alloc) yang mengembalikan buffer teks ke arena dan defer arena.deinit() yang mengembalikan seluruh blok arena ke sistem. Keduanya terdaftar sejak deklarasi, dan tidak ada satu pun pembebasan per potongan teks di dalam perulangan, sesuai rencana.
zig run laporan-arena.zigcabang Gambir: 120 unit
cabang Menteng: 85 unit
cabang Cempaka: 143 unit
total: 348 unit
baris laporan: 4Empat baris keluaran berasal dari tiga perulangan plus satu baris total, dengan angka 348 sebagai penjumlahan ketiga cabang. Setiap panggilan laporan.print menambah teks ke buffer yang tumbuh dinamis, dan seluruhnya kembali ke arena pada akhir fungsi tanpa pembukuan tambahan.
Bila program dikembangkan sehingga satu jenis data harus bertahan melebihi cakupan arena, datanya dipindahkan ke baris GPA pada tabel, dan perpindahannya menyentuh tempat yang terbatas. Allocator serbaguna pada 0.17.0 diperoleh dari std.heap.DebugAllocator, dan perbedaannya dengan arena terlihat langsung pada pembukuan pembebasannya.
// tidak-dijalankan
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const cache = try alloc.dupe(u8, "Gambir");
defer alloc.free(cache);Pemilik cache kini wajib membebaskannya sendiri, dan kontrak kepemilikan pada tanda tangan fungsi penerima menjadi kewajiban yang nyata. Perpindahan satu jenis data dari arena ke GPA menambah satu free, tetapi membebaskan arena dari tanggung jawab yang tidak sesuai masa hidupnya. Pemisahan ini adalah bentuk paling kecil dari disiplin yang dijaga tabel rencananya.
Kesalahan umum#
Kesalahan kedua berupa rencana yang hanya ada di kepala. Tabel keputusan yang tidak tertulis tidak dapat diverifikasi saat peninjauan kode, dan keputusan baris demi baris mulai menyimpang tanpa terasa. Berkas rencananya kecil, tetapi isinya dipakai setiap kali fungsi baru dibuat, dan ketidakcocokan barisnya menjadi sinyal untuk menghentikan penulisan sejenak.
Kesalahan ketiga berupa membebaskan alokasi arena satu per satu. Panggilan free pada allocator arena praktis tidak melakukan apa pun, sehingga kode yang menyebutnya tampak rajin tetapi tidak berdampak. Pembebasan arena berlangsung sekali pada deinit, dan pembacaan ulang topik ArenaAllocator menegaskan kontraknya.
Ringkasan#
- Rencana memori ditulis sebelum kode, berupa tabel keputusan yang memetakan jenis data ke masa hidup dan strateginya.
- Arena melayani data sementara dengan satu pembebasan, GPA melayani struktur lintas masa hidup, dan buffer stack melayani kebutuhan sesaat.
- Program pelaporan memusatkan seluruh potongan teksnya pada arena dengan dua
deferyang terdaftar sejak deklarasi. - Pemeriksa kebocoran memverifikasi rencana, bukan menggantikannya.
Topik penutup jalur ini menuntaskan proyek melalui titik-titik pemeriksaan yang berulang pada setiap tahap.
Referensi#
- Choosing-an-Allocator — Zig Language Reference — Panduan resmi memilih strategi allocator.
- std.heap.ArenaAllocator — Dokumentasi pustaka standar Zig — Arena untuk kelompok data yang seumur hidup.