php的編譯原理:
ze(zend engine)呼叫詞法分析器把php 程式碼去空格,注釋後分割成一個個token,ze呼叫語法分析器再對token處理形成opcode,opcode以op array形式存在,ze最後執行op array輸出結果。
當一個PHP執行緒結束時,當前佔用的所有記憶體空間都會被銷毀。那麼如果這個執行緒不結束,怎麼回收記憶體呢?
refcount:參照技術器,可以理解為指向該個容器的指標個數吧。
is_ref:是否被參照(只可能是0或者1)
賦值的流程:
<?php $a = 'aa'; xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6) $b = $a; //以下的兩個其實是一個變數容器 xdebug_debug_zval(a); //(refcount=2, is_ref=0),string 'aa' (length=6) xdebug_debug_zval(b); //(refcount=2, is_ref=0),string 'aa' (length=6) unset($b); //對變數容器 refcount 減1xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6) xdebug_debug_zval(b); //b: no such symbol b變數被銷毀,指向被斷掉,如果對應容器的參照技術為零,那麼該塊兒記憶體被回收 $b = $a; $b = 'bb'; xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6) xdebug_debug_zval(b); //(refcount=1, is_ref=0),string 'aa' (length=6) 重新申請一個變數容器儲存b,a的變數容器參照減1
參照的流程:
<?php $a = 'aa'; xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) $b = & $a;//變數容器的參照技術加1,參照標記置為1xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2) xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string 'aa' (length=2) $b = '123'; //php會發現,該容器變數是參照(is_ref),所以容器變數不用像賦值那樣再申請一個 xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string '123' (length=2) xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string '123' (length=2) unset($b);//變數容器應用計數減1,參照為零 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string '123' (length=2) xdebug_debug_zval('b'); // b: no such symbol
那如果多次參照,unset掉一個,is_ref是否會被置為零,那樣bug不就出現了麼?變數容器還是參照啊。那麼我們來看看:
<?php $a = 'aa'; $b = &$a; $c = &$a;//可以看到參照refCount是3,is_ref永遠是1xdebug_debug_zval('a'); //(refcount=3, is_ref=1),string 'aa' (length=2) xdebug_debug_zval('b'); //(refcount=3, is_ref=1),string 'aa' (length=2) xdebug_debug_zval('c'); //(refcount=3, is_ref=1),string 'aa' (length=2) unset($b);//我們期待的bug沒有出現,只是refcount減1,is_ref還是1xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2) xdebug_debug_zval('b'); // b: no such symbol xdebug_debug_zval('c'); //(refcount=2, is_ref=1),string 'aa' (length=2) //那php它怎麼知道這個容器還有參照,畢竟is_ref仍然是1,不能計數,那麼現在refcount就起作用了,是它告訴php,該變數有幾個參照,但問題又來了,如果我幹點壞事,在參照的時候,又賦值,它會不會有bug $e = $a;//我們看到期望的bug還是沒出現,這時候再賦值,就不像直接賦值那麼簡單refcount加1了,而是申請了一個新的變數容器 xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2) xdebug_debug_zval('e'); //(refcount=1, is_ref=0),string 'aa' (length=2)
unset和賦值null都能回收變數麼?很多人都錯認為,這兩個都能回收變數空間,其實錯了,null只是把變數占用的空間變小了,從回收上來說,該容器依然存在。
<?php $a = 'aa'; $b = $a; $b = null; //又申請了一個變數容器 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) xdebug_debug_zval('b'); //(refcount=1, is_ref=0),null 變數空間並沒被回收 unset($b); //這時候才釋放了b變數容器的空間 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) xdebug_debug_zval('b'); //b: no such symbol以上就是php垃圾回收機制(gc)介紹的詳細內容,更多請關注TW511.COM其它相關文章!