Manajemen Memori dan Pengumpulan Sampah
Lihat cara kerja zval, penghitungan referensi, dan GC.
Manajemen Memori dan Pengumpulan Sampah adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar PHP Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus PHP Academy mencakup 4 pelajaran total.
Cara PHP Mengelola Memori
Nilai PHP disimpan dalam zval, yang sebagian besar dikelola dengan penghitungan referensi, serta dilengkapi pengumpul siklus untuk menangani hal-hal yang tidak dapat ditangani penghitungan referensi. Memahami hal ini membantu menjelaskan kebocoran memori pada pekerja yang berjalan lama, biaya penyalinan, dan kapan gc_collect_cycles() diperlukan.
zval
zval adalah wadah untuk semua nilai PHP: penanda tipe ditambah union penyimpanan nilai. Nilai skalar (bilangan bulat, pecahan, boolean) disimpan berdasarkan nilai di dalam zval dan NOT dihitung referensinya. Tipe kompleks (teks, larik, objek) menunjuk ke struktur dengan penghitungan referensi di heap.
<?php
// debug_zval_refcount-style inspection via gc + count
$arr = [1, 2, 3];
$copy = $arr; // refcount of the array bumps, no data copy yet (CoW)
// Modifying triggers copy-on-write separation
$copy[] = 4;
var_dump($arr); // still [1,2,3]
var_dump($copy); // [1,2,3,4]
?>Penghitungan Referensi
Setiap nilai yang menggunakan penghitungan referensi melacak berapa banyak zval yang menunjuk kepadanya. Penetapan nilai menambah hitungannya; penghapusan atau keluarnya nilai dari cakupan menguranginya. Ketika hitungan mencapai nol, memori segera dibebaskan — tanpa menunggu proses pengumpulan sampah. Sebagian besar memori PHP diperoleh kembali dengan cara ini.
<?php
$a = str_repeat('x', 1000); // refcount 1 on the string
$b = $a; // refcount 2
unset($a); // refcount 1
unset($b); // refcount 0 -> freed instantly
echo "Refcounting frees deterministically\n";
?>Salin Saat Tulis
Penetapan nilai tidak menyalin data; data dibagikan dan hitungan referensinya dinaikkan (copy-on-write). Duplikasi sebenarnya baru terjadi saat penulisan pertama ke nilai yang dibagikan. Karena itu, meneruskan larik besar tidak mahal sampai larik tersebut diubah.
<?php
$big = range(1, 100000);
$shared = $big; // O(1): shared, refcount++
// Reads stay shared and cheap
echo count($shared), PHP_EOL;
// First write separates (copies) — now it costs O(n)
$shared[0] = -1;
echo $big[0], ' vs ', $shared[0], PHP_EOL; // 1 vs -1
?>Masalahnya: Siklus
Penghitungan referensi saja tidak dapat membebaskan siklus referensi. Jika objek A menyimpan referensi ke B dan B kembali ke A, hitungan keduanya tidak pernah mencapai nol meskipun semua variabel eksternal sudah dihapus — memori tersebut bocor sampai pengumpul siklus berjalan.
<?php
class Node { public ?Node $ref = null; }
$a = new Node();
$b = new Node();
$a->ref = $b; // a -> b
$b->ref = $a; // b -> a (cycle!)
unset($a, $b); // external refs gone, but internal cycle keeps refcount > 0
// The objects are unreachable but NOT yet freed by refcounting alone.
echo gc_collect_cycles() . " cycles collected\n";
?>Pengumpul Siklus
Pengumpulan sampah PHP menerapkan penandaan dan penyapuan sinkron pada akar. Akar siklus yang berpotensi (nilai yang hitungan referensinya dikurangi tetapi tidak mencapai nol) disimpan dalam penyangga. Ketika penyangga akar penuh (secara bawaan 10.000), pengumpulan sampah berjalan: proses ini menyimulasikan pengurangan, menemukan kelompok yang benar-benar tidak dapat dijangkau, lalu membebaskannya.
<?php
// GC status exposes the root buffer and run stats
for ($i = 0; $i < 3; $i++) {
$a = new stdClass();
$b = new stdClass();
$a->b = $b; $b->a = $a; // create a cycle
unset($a, $b); // becomes a GC root
}
print_r(gc_status());
?>Mengendalikan Pengumpulan Sampah
Anda dapat mengatur pengumpul tersebut: gc_disable()/gc_enable() mengaktifkan atau menonaktifkannya, sedangkan gc_collect_cycles() memaksa satu proses pengumpulan dan mengembalikan jumlah nilai yang dibebaskan. Dalam pekerjaan batch yang mengutamakan throughput, Anda kadang dapat menonaktifkan pengumpulan sampah selama tahap yang ketat, lalu menjalankannya sekali di akhir.
<?php
gc_disable(); // no automatic cycle collection
// ... heavy phase that creates and drops many cycles ...
for ($i = 0; $i < 1000; $i++) {
$x = new stdClass(); $y = new stdClass();
$x->y = $y; $y->x = $x; unset($x, $y);
}
$freed = gc_collect_cycles(); // reclaim all at once
gc_enable();
echo "Freed $freed objects\n";
?>Pekerja yang Berjalan Lama
Pada daemon CLI, konsumen antrean, serta pekerja Swoole/RoadRunner, memori tidak dibebaskan saat permintaan dibongkar — prosesnya tetap hidup selama berjam-jam. Waspadai: cache statis yang tumbuh tanpa batas, siklus yang terus menumpuk, dan sumber daya yang tidak ditutup. Pantau dengan memory_get_usage(true) dan mulai ulang pekerja secara berkala.
<?php
$peakStart = memory_get_usage(true);
// Simulate processing a batch of jobs
for ($job = 0; $job < 5; $job++) {
$payload = range(0, 10000);
// ... process ...
unset($payload);
}
printf("start: %d KB, peak: %d KB, now: %d KB\n",
$peakStart >> 10,
memory_get_peak_usage(true) >> 10,
memory_get_usage(true) >> 10
);
?>WeakReference & WeakMap
Untuk menyimpan cache atau mengaitkan data dengan objek tanpa membuatnya tetap hidup, gunakan WeakReference (8.0) dan WeakMap (8.0). Entri WeakMap tidak menambah hitungan referensi objek kunci, sehingga objek tersebut dapat dikumpulkan dan entrinya dihapus secara otomatis — ideal untuk tabel samping metadata yang tidak boleh bocor.
<?php
$map = new WeakMap();
$obj = new stdClass();
$map[$obj] = 'metadata'; // does NOT keep $obj alive
echo count($map) . PHP_EOL; // 1
unset($obj); // object collectible -> entry removed
echo count($map) . PHP_EOL; // 0
?>String Intern dan Nilai Tak Berubah
String harfiah dalam kode sumber Anda diinternalkan: disimpan satu kali, dibagikan, dan tidak pernah dihitung referensinya atau dibebaskan selama permintaan. OPcache memindahkan string yang diinternalkan dan larik kode operasi tak berubah (yang tersimpan) ke memori bersama di antara permintaan. Inilah sebabnya string harfiah pada dasarnya tidak memerlukan biaya saat disalin.
Batas Memori dan Pengalokator
PHP menggunakan pengalokator emalloc miliknya sendiri (Zend Memory Manager) yang dibangun di atas pengalokator sistem, serta melacak penggunaan per permintaan terhadap memory_limit. Jika batas tercapai, galat fatal akan muncul. Nilai true dalam memory_get_usage(true) melaporkan blok yang benar-benar dialokasikan oleh OS, bukan hanya yang sedang disimpan oleh skrip Anda.
<?php
echo 'limit: ' . ini_get('memory_limit') . PHP_EOL;
echo 'emalloc usage: ' . memory_get_usage() . " bytes\n"; // ZendMM tracked
echo 'real usage: ' . memory_get_usage(true) . " bytes\n"; // from OS
?>Pemeriksaan Singkat
Mengapa penghitungan referensi saja dapat menyebabkan sebagian objek bocor?
Ringkasan
PHP menyimpan nilai dalam zval; nilai skalar disimpan berdasarkan nilai, sedangkan tipe kompleks dialokasikan di heap dan menggunakan penghitungan referensi dengan salin saat tulis. Penghitungan referensi membebaskan memori secara deterministik saat hitungan mencapai nol, tetapi tidak dapat mengambil kembali siklus, sehingga pengumpul penandaan dan penyapuan sinkron berjalan saat penyangga akar penuh (atau melalui gc_collect_cycles()). Gunakan WeakMap/WeakReference untuk hubungan yang tidak memiliki objek, dan waspadai pertumbuhan tanpa batas pada pekerja yang berjalan lama.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Manajemen Memori dan Pengumpulan Sampah” gratis?
Ya — teks lengkap “Manajemen Memori dan Pengumpulan Sampah” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus PHP Academy, upgrade ke CoddyKit PRO. Kursus PHP Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Manajemen Memori dan Pengumpulan Sampah”?
Lihat cara kerja zval, penghitungan referensi, dan GC. Kamu berlatih PHP Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai PHP Academy?
Tidak diperlukan pengalaman sebelumnya. PHP Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Manajemen Memori dan Pengumpulan Sampah” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran PHP Academy ini?
Ya. Setiap pelajaran PHP Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Cara Kerja Zend Engine
- Manajemen Memori dan Pengumpulan Sampah
- OPcache dan Kompilasi JIT
- Menulis Ekstensi PHP Dasar dalam C