PHP 採用「複製時寫入」與「參考計數」機制管理記憶體。理解 `refcount`、`is_ref` 運作原理,對於編寫高效能、無記憶體洩漏的長期執行腳本(如 CLI 常駐程式、Swoole 服務)至關重要。
| 概念 | 說明 |
|---|---|
| refcount | 指向同一 zval 容器的變數個數(參考計數器) |
| is_ref | 標記該容器是否為「參考集合」一員(0=否,1=是) |
| zval | PHP 內部儲存變數值的容器,包含 type、value、refcount、is_ref |
$a = 'aa'; // refcount=1, is_ref=0 $b = $a; // refcount=2, is_ref=0(共用同一容器) unset($b); // refcount=1, $b 銷毀 $b = $a; // refcount=2 $b = 'bb'; // 觸發 Copy-on-Write:$b 分配新容器,$a refcount=1
$a = 'aa'; // refcount=1, is_ref=0 $b = &$a; // refcount=2, is_ref=1(標記為參考集合) $b = '123'; // 直接修改共用容器,$a 也變成 '123' unset($b); // refcount=1, is_ref=0(參考解除,恢復一般變數)
$a = 'aa'; $b = &$a; // refcount=2, is_ref=1 $c = &$a; // refcount=3, is_ref=1 unset($b); // refcount=2, is_ref=1(不歸零,is_ref 維持 1) $e = $a; // 參考集合中複製:$e 分配新容器,refcount=1, is_ref=0
| 操作 | refcount 變化 | 記憶體釋放 | 說明 |
|---|---|---|---|
| unset($var) | -1 | 歸零時釋放 | 斷開變數與容器連結 |
| $var = null | 不變(或新增容器) | 不釋放 | 容器仍存在,值變為 null |
$a = 'aa'; $b = $a; $b = null; // $b 指向新的 null 容器,$a 不受影響 unset($b); // 此時 $b 容器才真正被回收
$a = "data"; $b = &$a; // 顯式參考,refcount+1, is_ref=1 unset($a); // $a 消失,但 $b 仍指向該記憶體 → 不會釋放
PHP 的記憶體管理核心在於「參考計數 + 複製時寫入」。掌握 `refcount`、`is_ref`、Copy-on-Write、循環引用檢測這幾個關鍵機制,才能真正掌控記憶體行為,避免長期執行程式的記憶體洩漏問題。