PHP 是一門受控語言,開發者無需手動分配/釋放記憶體,底層由 Zend 引擎實作垃圾回收(GC)。PHP 5.2 與 5.3 並行維護一段時間,5.3 引入重大 GC 改良,解決 5.2 版本的循環引用記憶體洩漏問題。
PHP 內部所有變數皆以 zval(_zval_struct)表示,包含值、類型、引用計數(refcount__gc)與是否為引用(is_ref__gc)。引用計數記錄有多少變數指向同一 zval,配合「寫時複製」(Copy-on-Write)機制運作。
機制直觀:建立物件時計數 = 1,新增引用 +1,釋放引用 -1,計數歸零即回收記憶體。
<?php
$a = array();
$a[] = & $a; // 陣列元素引用自身
unset($a); // $a 消失,但底層 zval refcount = 1(被自身元素引用),永不回收
?>
此類洩漏在短生命週期腳本(如網頁請求)中可忽略,但長期運行的 Daemon 進程會累積嚴重洩漏。
基於 IBM 論文 Concurrent Cycle Collection in Reference Counted Systems,核心概念:
測試腳本建立 100,000 個含循環引用的物件:
效能開銷:啟用 GC 執行 1,000,000 次循環約 7.2 秒,關閉約 6.4 秒(約 12% 慢),但換來穩定記憶體表現,值得。
zend.enable_gc (php.ini) 或 gc_enable()/gc_disable() 開關 GC。gc_collect_cycles() 強制執行。PHP 5.3 的 GC 演進是里程碑,使 PHP 適用於長期運行的高併發服務。理解其運作原理有助於撰寫更健壯的程式碼,避免無意中製造難以回收的循環引用結構。