首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

深入解析 PHP unset() 是否真釋放記憶體

     編輯:PHP 相關知識

關於 PHP 中 unset() 是否真正釋放記憶體,開發者間向來眾說紛紜。有人認為它不釋放記憶體,有人說只在大變量時才釋放,更有人認為在 PHP 層面討論記憶體毫無意義。本文將通過實例與底層原理,徹底釐清這個問題。

現象觀察:那 32 位元組去哪了?

先看一段簡單代碼:

<?php
var_dump(memory_get_usage());
$a = "laruence";
var_dump(memory_get_usage());
unset($a);
var_dump(memory_get_usage());

輸出可能如下(數值因環境而異):

int(90440)
int(90640)
int(90472)

變量賦值後記憶體增加 200 位元組,unset() 後只減少 168 位元組,殘留 32 位元組。這 32 位元組究竟去哪了?

打破誤區:PHP 的記憶體分配非顯式

PHP 不同於 C 語言,並非只有顯式調用分配 API 才會分配記憶體。對於 $a = "laruence" 這行代碼,隱式分配包括:

  1. 為變量名在符號表中分配記憶體
  2. 為變量值(zval 結構)分配記憶體

因此不能只看表象,必須深入底層機制。

核心結論:unset() 確實釋放記憶體,但非歸還給 OS

PHP 內部實現了一套類似 C 的記憶體管理 API(emalloc/efree)。調用 emalloc 時,PHP 會向 OS 申請大塊記憶體,再從中切分分配;調用 efree 時,記憶體不會歸還 OS,而是歸入 PHP 維護的空閒列表或緩存列表,供下次複用。這避免了頻繁系統調用,提升性能。

驗證實例(使用 memory_get_usage(true) 獲取真實分配量):

<?php
var_dump(memory_get_usage(true)); // 262144
$a = "laruence";
var_dump(memory_get_usage(true)); // 262144
unset($a);
var_dump(memory_get_usage(true)); // 262144

可見定義變量時 PHP 未向 OS 申請新記憶體,unset() 後實際分配量也未變,記憶體被內部緩存複用。

揭秘 32 位元組的真相

為何第一個例子會殘留 32 位元組?關鍵在於 var_dump() 輸出本身會佔用記憶體(嚴格說是輸出緩衝區 Header)。看對比實驗:

<?php
var_dump("I am www.jb51.net");
var_dump(memory_get_usage()); // 90808
$a = "laruence";
var_dump(memory_get_usage()); // 90976
unset($a);
var_dump(memory_get_usage()); // 90808

前後記憶體一致(90808 - 90808 = 0),證明那 32 位元組確實被輸出函數佔用,unset() 實際上已正常釋放變量記憶體。

只增不減的 Hashtable 與符號表

PHP 的數組與符號表底層均為 Hashtable。Hashtable 初始化只分配少量桶,不足時擴容(resize),只擴不縮。實例:

<?php
var_dump("I am www.jb51.net");
var_dump(memory_get_usage()); // 93560
$array = array_fill(1, 100, "laruence");
foreach ($array as $key => $value) {
    ${$value . $key} = NULL;
}
var_dump(memory_get_usage()); // 118848
foreach ($array as $key => $value) {
    unset(${$value . $key});
}
var_dump(memory_get_usage()); // 104448

創建 100 個變量後記憶體增長,unset 後釋放了變量值記憶體(118848 - 104448 = 14400),但符號表 Hashtable 因擴容而保留的桶結構未縮小,佔用了剩餘記憶體。

總結

  • unset() 確會釋放變量值(zval)記憶體,歸入 PHP 內部緩存池,供下次分配複用,不歸還 OS。
  • 符號表 Hashtable 只擴不縮,大量創建變量後雖 unset,符號表結構仍佔用記憶體。
  • PHP 記憶體管理採用「預分配 + 緩存池」策略,減少系統調用開銷,適合 Web 請求的短生命周期模型。

理解機制後,不必過度糾結微小殘留,專注業務邏輯與大對象釋放(如大數組、大字符串)才是性能優化關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved