PHP線程的內(nèi)存回收問(wèn)題
當(dāng)一個(gè)PHP線程結(jié)束時(shí),當(dāng)前占用的所有內(nèi)存空間都會(huì)被銷毀。那么如果這個(gè)線程不結(jié)束,怎么回收內(nèi)存呢?
refcount:引用技術(shù)器,可以理解為指向該個(gè)容器的指針個(gè)數(shù)吧。
is_ref:是否被引用(只可能是0或者1)
賦值的流程:
<?php $a = 'aa'; xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6) $b = $a; //以下的兩個(gè)其實(shí)是一個(gè)變量容器 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); //對(duì)變量容器 refcount 減1 xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6) xdebug_debug_zval(b); //b: no such symbol b變量被銷毀,指向被斷掉,如果對(duì)應(yīng)容器的引用技術(shù)為零,那么該塊兒內(nèi)存被回收 $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) 重新申請(qǐng)一個(gè)變量容器存儲(chǔ)b,a的變量容器引用減1
引用的流程:
<?php $a = 'aa'; xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) $b = & $a; //變量容器的引用技術(shù)加1,引用標(biāo)記置為1 xdebug_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會(huì)發(fā)現(xiàn),該容器變量是引用(is_ref),所以容器變量不用像賦值那樣再申請(qǐng)一個(gè) 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); //變量容器應(yīng)用計(jì)數(shù)減1,引用為零 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string '123' (length=2) xdebug_debug_zval('b'); // b: no such symbol
那如果多次引用,unset掉一個(gè),is_ref是否會(huì)被置為零,那樣bug不就出現(xiàn)了么?變量容器還是引用啊。那么我們來(lái)看看:
<?php $a = 'aa'; $b = &$a; $c = &$a; //可以看到引用refCount是3,is_ref永遠(yuǎn)是1 xdebug_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沒(méi)有出現(xiàn),只是refcount減1,is_ref還是1 xdebug_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它怎么知道這個(gè)容器還有引用,畢竟is_ref仍然是1,不能計(jì)數(shù),那么現(xiàn)在refcount就起作用了,是它告訴php,該變量有幾個(gè)引用,但問(wèn)題又來(lái)了,如果我干點(diǎn)壞事,在引用的時(shí)候,又賦值,它會(huì)不會(huì)有bug $e = $a; //我們看到期望的bug還是沒(méi)出現(xiàn),這時(shí)候再賦值,就不像直接賦值那么簡(jiǎn)單refcount加1了,而是申請(qǐng)了一個(gè)新的變量容器 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都能回收變量么?很多人都錯(cuò)認(rèn)為,這兩個(gè)都能回收變量空間,其實(shí)錯(cuò)了,null只是把變量占用的空間變小了,從回收上來(lái)說(shuō),該容器依然存在。
<?php $a = 'aa'; $b = $a; $b = null; //又申請(qǐng)了一個(gè)變量容器 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) xdebug_debug_zval('b'); //(refcount=1, is_ref=0),null 變量空間并沒(méi)被回收 unset($b); //這時(shí)候才釋放了b變量容器的空間 xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2) xdebug_debug_zval('b'); //b: no such symbol
總結(jié)
1. 垃圾回收的時(shí)機(jī)
PHP中,引用計(jì)數(shù)為0,則內(nèi)存立刻釋放。也就是說(shuō),不存在環(huán)狀引用的變量,離開(kāi)變量的作用域,內(nèi)存被立刻釋放。環(huán)狀引用檢測(cè)則是在滿足一定條件下觸發(fā),所以在上面的例子中,會(huì)看到使用的內(nèi)存有大幅度的波動(dòng)。也可以通過(guò) gc_collect_cycles 函數(shù)來(lái)主動(dòng)進(jìn)行環(huán)狀引用檢測(cè)。
2. &符號(hào)的影響
顯式引用一個(gè)變量,會(huì)增加該內(nèi)存的引用計(jì)數(shù):
$a = "something";
$b = &$a;
此時(shí)unset($a), 但是仍有$b指向該內(nèi)存區(qū)域的引用,內(nèi)存不會(huì)釋放。
3. unset函數(shù)的影響
unset只是斷開(kāi)一個(gè)變量到一塊內(nèi)存區(qū)域的連接,同時(shí)將該內(nèi)存區(qū)域的引用計(jì)數(shù)-1;在上面的例子中,循環(huán)體內(nèi)部,$a=new A(); unset($a);并不會(huì)將$a的引用計(jì)數(shù)減到零;
4. = null 操作的影響;
$a = null 是直接將$a 指向的數(shù)據(jù)結(jié)構(gòu)置空,同時(shí)將其引用計(jì)數(shù)歸0。
5. 腳本執(zhí)行結(jié)束的影響
腳本執(zhí)行結(jié)束,該腳本中使用的所有內(nèi)存都會(huì)被釋放,不論是否有引用環(huán)。
相關(guān)文章
PHP設(shè)計(jì)模式之模板方法模式實(shí)例淺析
這篇文章主要介紹了PHP設(shè)計(jì)模式之模板方法模式,結(jié)合實(shí)例形式簡(jiǎn)單分析了php設(shè)計(jì)模式中模板方法模式的概念、原理、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-12-12php數(shù)組函數(shù)序列之a(chǎn)rray_sum() - 計(jì)算數(shù)組元素值之和
array_sum() 函數(shù)返回?cái)?shù)組中所有值的總和。如果所有值都是整數(shù),則返回一個(gè)整數(shù)值。如果其中有一個(gè)或多個(gè)值是浮點(diǎn)數(shù),則返回浮點(diǎn)數(shù)2011-10-10PHP中Too few arguments to function的問(wèn)題及解決
這篇文章主要介紹了PHP中Too few arguments to function的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02PHP 5.3.1 安裝包 VC9 VC6不同版本的區(qū)別是什么
php官網(wǎng)提供了四個(gè)版本,VC9 x86 Non Thread Safe、VC9 x86 Thread Safe、VC6 x86 Non Thread Safe、VC6 x86 Thread Safe,大家看完這篇文章就知道應(yīng)該選擇什么樣的版本了。2010-07-07

PHP 面向?qū)ο蟾倪M(jìn)后的一點(diǎn)說(shuō)明

PHP基于面向?qū)ο髮?shí)現(xiàn)的留言本功能實(shí)例

php實(shí)現(xiàn)常見(jiàn)圖片格式的水印和縮略圖制作(面向?qū)ο?