許多開發者誤以為 unset() 會立即釋放變數佔用的記憶體,實際上 PHP 內部採用引用計數與複製寫入(Copy-on-Write)機制,釋放時機受變數大小、引用關係影響。本文透過實測數據揭示真相。
測試碼:建立不同長度字串,記錄 unset() 前後記憶體差異:
for ($i = 1; $i < 100; $i++) {
$str = str_repeat('01234567', $i); // 每次增長 8 位元組
$a = memory_get_usage();
unset($str);
$b = memory_get_usage();
echo $i . ': ' . ($b - $a) . " Bytes\n";
}
關鍵發現:
結論一:unset() 僅在變數值超過 256 位元組 時才真正釋放記憶體(PHP 內部小字串優化機制)。
$s = str_repeat('1', 256);
$p = &$s; // $p 參考 $s
$m = memory_get_usage();
unset($s); // 僅解除 $s 綁定
$mm = memory_get_usage();
echo $p; // 仍輸出 256 個 1
echo $m - $mm; // -48(記憶體反而增加!)
因為 $p 仍持有引用,記憶體未釋放。若改用 $s = null 或雙重 unset():
$s = str_repeat('1', 256);
$p = &$s;
$m = memory_get_usage();
$s = null; // 或 unset($s); unset($p);
$mm = memory_get_usage();
echo $p; // 空字串
echo $m - $mm; // 224(成功釋放)
結論二:只有當 所有指向該資料的變數(含引用)都被銷毀,記憶體才會真正回收。
unset() 不再需要的大變數&$var),除非明確需要修改原值gc_collect_cycles() 強制垃圾回收(PHP 5.3+)yield)逐筆處理而非載入整個資料集理解 PHP 記憶體管理細節,能有效避免「明明 unset 了卻記憶體不降」的困擾,編寫更高效能的長執行腳本。