Setiap alokasi memori di Odin memakai salah satu dari dua alokator yang terpasang pada context, yaitu alokator default untuk data yang bertahan dan temp_allocator untuk memori sementara. Topik ini membahas identitas dan perilaku keduanya, kapan masing-masing dipilih, serta satu program pembanding yang memakai keduanya dalam satu alur kerja pencatatan suhu. Setelah topik ini, keputusan menaruh data di heap atau di penyimpanan sementara dapat diambil berdasarkan umur pakai datanya.
Alokator default heap dan identitasnya#
Alokator default adalah alokator heap yang disediakan runtime Odin, yaitu penyimpanan dinamis yang meminta blok memori baru ke sistem operasi dan mencatat setiap blok yang dikeluarkannya. Field context.allocator menunjuk ke alokator heap itu sejak proc main dimulai, dan setiap make tanpa argumen alokator mendarat di situ. Identitas alokator ini dapat diperiksa karena proc alokatornya bernama default_allocator_proc di paket base:runtime, sehingga perbandingan context.allocator.procedure == runtime.default_allocator_proc menghasilkan true pada program yang belum mengganti alokator. Field context.temp_allocator juga sudah terpasang sejak awal dengan arena bawaan runtime berukuran 4 megabyte, sesuai konstanta DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE pada sumber runtime. Dua fasilitas ini siap dipakai tanpa inisialisasi apa pun, sehingga program pertama yang memanggil make sudah memakai keduanya secara benar.
Perbandingan identitas itu berguna ketika program perlu memastikan alokator mana yang sedang aktif sebelum memilih strategi penanganan memori. Proc alokator tersimpan sebagai nilai proc biasa pada field procedure, sehingga perbandingannya berupa perbandingan alamat proc dan tidak memicu alokasi apa pun. Alokasi pada heap bawaan mengembalikan blok yang diisi nol karena mode yang dipakai make adalah .Alloc, sedangkan blok yang dilepaskan melalui delete kembali ke alokator penopang heap bawaan runtime.
Alokator temp dan cara meresetnya#
temp_allocator berperilaku seperti arena, yaitu alokator yang hanya menaikkan pointer dan tidak mencatat alokasi satu per satu. Alokasi dari temp sangat murah, tetapi harganya adalah disiplin umur pakai: seluruh isi temp dibuang sekaligus ketika free_all(context.temp_allocator) dipanggil, dan tidak ada cara melepas satu alokasi temp secara terpisah. Pustaka core memakai temp untuk hasil yang berumur sangat pendek, misalnya fmt.tprintf yang mengalokasikan string hasil format dari temp_allocator, berbeda dengan fmt.aprintf yang menerima alokator secara eksplisit. Pengisian temp menaikkan pemakaian hingga arena bawaannya penuh, dan arena tersebut tumbuh dengan meminjam memori dari alokator penopang. Karena itu, free_all tetap wajib dipanggil secara berkala pada program berumur panjang agar pemakaian memori tidak merambat naik. Pola yang lazim adalah satu panggilan free_all per putaran kerja, misalnya di akhir frame atau di akhir satu batch pemrosesan.
Kapan heap dan temp dipilih#
Kriteria penentuannya adalah umur pakai data, bukan ukurannya. Tabel berikut merangkum pemetaan itu beserta cara melepaskan masing-masing.
| Aspek | Alokator default (heap) | temp_allocator (scratch) |
|---|---|---|
| Umur pakai | Bertahan melewati lingkup dan putaran kerja | Hanya di dalam satu lingkup atau satu putaran |
| Contoh pemakaian | Catatan sensor, struktur data inti program | String hasil format, buffer cetak sementara |
| Cara melepaskan | delete atau free per alokasi | free_all untuk seluruh isi sekaligus |
| Biaya alokasi | Lebih mahal karena pencatatan per blok | Sangat murah, hanya menaikkan pointer |
| Risiko utama | Kebocoran bila lupa dilepaskan | Pointer mati bila data lolos dari lingkup |
Pola pemakaian yang sehat memisahkan keduanya pada batas yang sama. Satu putaran kerja, misalnya satu frame game atau satu batch pembacaan sensor, mengalokasikan seluruh data kerjanya dari temp, memproses atau mencetak dengan data itu, lalu mengosongkan temp pada akhir putaran. Data yang lolos dari putaran, seperti hasil yang dikumpulkan, dialihkan ke heap pada saat lahir. Dengan pemisahan itu, pemakaian temp kembali ke nol di setiap akhir putaran, sedangkan pertumbuhan heap hanya mengikuti data yang memang diminta untuk bertahan.
Program pembanding laporan suhu#
Program berikut mengoperasikan keduanya pada satu alur kerja: string laporan dicetak dari temp, sedangkan catatan historis tersimpan di heap. Baris terakhir membuktikan bahwa reset temp tidak menyentuh heap.
package main
import "base:runtime"
import "core:fmt"
// catatan yang harus bertahan sampai akhir program
catatan_suhu: [dynamic]f32
tambah_catatan :: proc(nilai: f32) {
append(&catatan_suhu, nilai)
}
main :: proc() {
fmt.println("alokator default adalah heap runtime:", context.allocator.procedure == runtime.default_allocator_proc)
fmt.println("alokator temp bawaan tersedia:", context.temp_allocator.data != nil)
suhu := [5]f32{28.4, 29.1, 30.2, 28.9, 29.7}
for nilai in suhu {
// tprintf mengalokasikan string laporan dari context.temp_allocator
// string ini hanya hidup selama baris laporan dicetak
laporan := fmt.tprintf("laporan suhu: %.1f derajat", nilai)
fmt.println(laporan)
// data historis dialokasikan dari context.allocator (heap)
tambah_catatan(nilai)
}
// seluruh memori temp dikosongkan dalam satu langkah
err := free_all(context.temp_allocator)
fmt.println("error free_all memori temp:", err)
// heap tidak terpengaruh oleh reset memori temp
fmt.println("jumlah catatan di heap:", len(catatan_suhu))
total := f32(0)
for nilai in catatan_suhu {
total += nilai
}
fmt.printf("rata-rata suhu: %.2f derajat\n", total / f32(len(catatan_suhu)))
}# sumberkan lingkungan sandbox jalur odin bila belum tersedia
[ -f /home/kal/my-project/tools/env.sh ] && source /home/kal/my-project/tools/env.sh
# jalankan program dari dalam folder topik
odin run main.odin -filealokator default adalah heap runtime: true
alokator temp bawaan tersedia: true
laporan suhu: 28.4 derajat
laporan suhu: 29.1 derajat
laporan suhu: 30.2 derajat
laporan suhu: 28.9 derajat
laporan suhu: 29.7 derajat
error free_all memori temp: None
jumlah catatan di heap: 5
rata-rata suhu: 29.26 derajatDua baris pertama membuktikan identitas keduanya. Setiap putaran perulangan mengalokasikan string laporan dari temp dan menambah satu nilai ke dynamic array di heap. Penambahan pada dynamic array dialokasikan dari context.allocator karena append memakai alokator context. Panggilan free_all mengembalikan None karena reset memori temp berhasil, sedangkan catatan di heap tetap utuh sehingga rata-rata bisa dihitung setelahnya.
Perhatikan juga apa yang tidak dilakukan program ini. String laporan tidak dilepaskan satu per satu karena lahir di temp dan dibuang oleh free_all sekaligus, sedangkan catatan_suhu sengaja bertahan sampai akhir program dan pelepasannya ditangani pada bagian akhir proses. Pembagian kerja dalam satu putaran seperti ini adalah bentuk paling sederhana dari manajemen memori per frame, dan menjadi dasar pemanfaatan arena yang lebih menyeluruh. Pengukuran identitas pada dua baris pertama sekaligus membuktikan bahwa tidak ada inisialisasi alokator yang perlu ditulis.
Kesalahan umum#
Kesalahan pertama adalah menyimpan hasil fmt.tprintf sampai melewati titik reset. String itu lahir di dalam area yang dikosongkan oleh free_all, sehingga menyimpannya di field struct berarti menyimpan pointer ke memori yang tidak lagi sah. Nilai yang harus bertahan disalin ke alokator default terlebih dahulu, misalnya dengan strings.clone yang mengalokasikan salinannya dari context.allocator, atau dibuat dengan fmt.aprintf yang menerima alokator secara eksplisit.
Kesalahan kedua adalah mengalokasikan data jangka panjang di temp dengan menuliskan context.temp_allocator sebagai argumen make. Alokasinya berhasil dan pengujian di lingkungan pengembangan tampak baik, tetapi pemakaian pertama setelah free_all menyentuh memori yang sudah dikosongkan. Kriteria pilihannya tetap sama, yaitu umur pakai data, dan argumen alokator eksplisit pada make hanya dipakai untuk data yang memang mati bersama lingkunya.
Ringkasan#
context.allocatorbawaan adalah alokator heap runtime dengan procruntime.default_allocator_proc, sedangkancontext.temp_allocatoradalah arena bawaan berukuran 4 megabyte.- Memori temp hanya dikosongkan sekaligus melalui
free_all, sehingga hanya cocok untuk data yang tidak lolos dari lingkup atau putaran kerja. - Data yang bertahan melewati lingkup dialokasikan dari heap dan dilepaskan per alokasi dengan
delete. fmt.tprintfmemakaitemp_allocator, sedangkanfmt.aprintfmenerima alokator secara eksplisit.
Referensi#
- Overview — Odin Documentation — Panduan resmi dengan bagian Allocators dan temp allocator.
- Paket core:mem — Referensi pustaka Odin
— Dokumentasi
free_all,alloc, dan keluarga proc alokator.