先看一段代碼:php
定義變量以後,內存增長,清除變量以後,內存恢復(有些可能不會恢復和之前同樣),好像定義變量時申請了一次內存,其實不是這樣的,php會預先申請一塊內存,不會每次定義變量就申請內存。編程
首先咱們要打破一個思惟: PHP不像C語言那樣, 只有你顯示的調用內存分配相關API纔會有內存的分配. 也就是說, 在PHP中, 有不少咱們看不到的內存分配過程.
好比對於:
$a = "laruence";
隱式的內存分配點就有:
1.1. 爲變量名分配內存, 存入符號表
2.2. 爲變量值分配內存
因此, 不能只看表象.
第二, 別懷疑,PHP的unset確實會釋放內存, 但這個釋放不是C編程意義上的釋放, 不是交回給OS.
對於PHP來講, 它自身提供了一套和C語言對內存分配類似的內存管理API: 數組
這些API和C的API意義對應, 在PHP內部都是經過這些API來管理內存的.
當咱們調用emalloc申請內存的時候, PHP並非簡單的向OS要內存, 而是會像OS要一個大塊的內存, 而後把其中的一塊分配給申請者, 這樣當再有邏輯來申請內存的時候, 就再也不須要向OS申請內存了, 避免了頻繁的系統調用.緩存
好比如下的例子:app
也就是咱們在定義變量$a的時候, PHP並無向系統申請新內存.一樣的, 在咱們調用efree釋放內存的時候, PHP也不會把內存還給OS, 而會把這塊內存, 納入本身維護的空閒內存列表. 而對於小塊內存來講, 更可能的是, 把它放到內存緩存列表中去spa
只增不減的數組
Hashtable是PHP的核心結構, 數組也是用她來表示的, 而符號表也是一種關聯數組, 對於以下代碼:debug
咱們定義了100個變量, 而後又按個Unset了他們, 來看看輸出:code
怎麼少了這麼多內存?
這是由於對於Hashtable來講, 定義它的時候, 不可能一次性分配足夠多的內存塊, 來保存未知個數的元素, 因此PHP會在初始化的時候, 只是分配一小部份內存塊給HashTable, 當不夠用的時候再RESIZE擴容。而Hashtable, 只能擴容, 不會減小,對象
對於上面的例子, 當咱們存入100個變量的時候, 符號表不夠用了, 作了一次擴容, 而當咱們依次unset掉這100個變量之後, 變量佔用的內存是釋放了(118848 – 104448), 可是符號表並無縮小, 因此這些少的內存是被符號表自己佔去了…blog
2、垃圾回收機制
PHP變量存儲在一個zval容器裏面的
1.變量類型
2. 變量值
3. is_ref 表明是否有地址引用
4. refcount 指向該值的變量數量
變量賦值的時候:is_ref爲false, refcount爲1
輸出:
將變量a的值賦給變量b,變量b不會馬上去在內存中存儲值,而是先指向變量a的值,一直到變量a有任何操做的時候
輸出:
輸出:
由於程序又操做了變量a,因此變量b會本身申請一塊內存將值放進去。
因此變量a的zval容器中refcount會減1變爲1,變量c指向a,因此refcount會加1變爲2,is_ref變爲true
垃圾回收
1.在5.2版本或以前版本,PHP會根據refcount值來判斷是否是垃圾
若是refcount值爲0,PHP會當作垃圾釋放掉
這種回收機制有缺陷,對於環狀引用的變量沒法回收
環狀引用:
輸出:
2.在5.3以後版本改進了垃圾回收機制若是發現一個zval容器中的refcount在增長,說明不是垃圾若是發現一個zval容器中的refcount在減小,若是減到了0,直接當作垃圾回收若是發現一個zval容器中的refcount在減小,並無減到0,PHP會把該值放到緩衝區,當作有多是垃圾的懷疑對象當緩衝區達到臨界值,PHP會自動調用一個方法取遍歷每個值,若是發現是垃圾就清理