php垃圾回收機制(gc)介紹

2020-07-16 10:05:54

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其它相關文章!