PHP進行內存管理的核心算法一共兩項:一是引用計數,二是寫時拷貝,請(please)理(bei)解(song)
1.引用計數
使用的是“引用計數”方式進行回收。
簡單地理解的話,就是每個分配的內存區域都有一個計數器,記錄有多少個變量指針指向這片內存。當指向該片內存的指針數量爲0,那麼該片內存區域就可以被回收。
引用計數計數簡單,強大,但是有一個致命的缺陷,就是環狀引用。
code:
<?php
$a = [];
$a[] = &$a;
unset($a);
變量$a引用了自己,形成一個環。$a被unset,但由於存在環狀引用,因此$a之前指向的內存的引用計數爲1,因此該內存區域不會被垃圾回收機制回收。
PHP5.3針對這個重大的缺陷做了優化。雖然其基礎仍然是引用計數,但是在做了一些改良,能夠將環狀引用導致的內存泄露控制在一定的規模以內。
當然,這並不是說你可以隨便濫用內存,編寫代碼時仍然要小心爲上!//this is the key point!!
其他要點:
1.PHP腳本運行完畢,該腳本申請的所有內存空間都會釋放,不管是否存在環狀引用。因此環狀引用內存泄露的問題一般隻影響長時間運行的程序腳本。
2.垃圾回收機制需要滿足一定的條件纔會執行。因此unset後,系統並不一定會立即回收垃圾。
3.unset的作用。 “unset只是斷開一個變量到一塊內存區域的連接,同時將該內存區域的引用計數-1”。也就是說,如果有一個以上的變量指向同一個內存區域,或者存在環狀引用,那麼unset不會使內存區域釋放。斷開也說明unset並不會直接刪除內存區域,而只是改變其引用計數而已。
4.$xx=null的作用。
“$a = null 是直接將$a 指向的數據結構置空,同時將其引用計數歸0”。根據我對這個定義的理解,=null操作可以立即釋放掉內存空間!因此很多PHP技巧中不厭其煩地對我們說,先將變量設爲null,再unset。理解其深層原理後,我才徹底理解了這樣做的原因!=null纔是王道!
|
2.寫時拷貝
即:變量的普通賦值與引用賦值
兩者的區別:
https://blog.csdn.net/william_n/article/details/93601962
<?php
// 先不要問爲什麼非要加mt_rand,不然,絕筆說不過來了,到處都是坑
$a = 'hello'.mt_rand( 1, 1000 );
$b = $a;
$a = 123;
echo $b.PHP_EOL;
// 運行結果,不用我說吧,腳趾頭都知道是'hello'.mt_rand( 1, 1000 )的結果,絕對不可能是123。
其實,當你把$a賦值給$b的時候,$a的值並沒有真的複製了一份,這樣是對內存的極度不尊重,也是對時間複雜度的極度不尊重,計算機僅僅是將$b指向了$a的值而已,這就叫多快好省。
那麼,什麼時候真正的發生複製呢?就是當我們修改$a的值爲123的時候,這個時候就不得已進行復制,避免$b的值和$a的一樣。
Q: 什麼樣的情況會導致zend_value的refcount不爲0,但是這個zend_value卻是個垃圾呢?
A: PHP7種兩種情況:
-
數組:數組的某個成員使用&引用自己
-
對象:對象的某個成員引用對象自己
請理(bei)解(song),一般面試,你能回答到這一步,已經非常屌了!
|
3. 垃圾回收函數 //使用哪些函數可以進行垃圾回收
4.資源參考:
後續補充...