溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP的垃圾回收機(jī)制相關(guān)知識(shí)點(diǎn)整理

發(fā)布時(shí)間:2021-09-03 19:29:24 來(lái)源:億速云 閱讀:132 作者:chen 欄目:編程語(yǔ)言

本篇內(nèi)容主要講解“PHP的垃圾回收機(jī)制相關(guān)知識(shí)點(diǎn)整理”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“PHP的垃圾回收機(jī)制相關(guān)知識(shí)點(diǎn)整理”吧!

PHP目前的開(kāi)發(fā)框架,除了主流常用的FPM框架,想必就是基于swoole拓展的常駐內(nèi)存開(kāi)發(fā)了。

我們?cè)贔PM的開(kāi)發(fā)模式中,每一次腳本程序結(jié)束之后,所有變量都會(huì)被銷毀,內(nèi)存會(huì)被釋放,所以我們不用太擔(dān)心。

但是常駐內(nèi)存開(kāi)發(fā)模式就不一樣了,如果不注意變量?jī)?nèi)存的使用,無(wú)法很好的管理內(nèi)存問(wèn)題,會(huì)造成內(nèi)存泄露。

所以,我們一定要熟悉PHP的垃圾回收機(jī)制(Garbage Collector 簡(jiǎn)稱GC) 

寫(xiě)時(shí)復(fù)制與引用計(jì)數(shù)

寫(xiě)時(shí)復(fù)制

在PHP7+版本中,有關(guān)于變量?jī)?nèi)存的操作特性,采用了寫(xiě)時(shí)復(fù)制,也就是說(shuō), 在必要的時(shí)候才會(huì)進(jìn)行深拷貝(即發(fā)生寫(xiě)的時(shí)候才會(huì)進(jìn)行深拷貝).

當(dāng)變量值為interned string字符串型(變量名,函數(shù)名,靜態(tài)字符串,類名等)時(shí),變量值存儲(chǔ)在靜態(tài)區(qū),內(nèi)存回收被系統(tǒng)全局接管,引用計(jì)數(shù)將一直為1 。

當(dāng)賦值變量的值為 整型,浮點(diǎn)型 時(shí),php7底層將會(huì)直接把值存儲(chǔ)(php7的結(jié)構(gòu)體將會(huì)直接存儲(chǔ)簡(jiǎn)單數(shù)據(jù)類型),refcount將為0,我們用代碼來(lái)看一下:

$a = 'chris'.time();$b = $a;  //此時(shí)$b指向$a的同一個(gè)內(nèi)存地址$c = $a;  //一樣xdebug_debug_zval('a');//a:(refcount=3, is_ref=0)string 'chris1614780053' (length=15)我們通過(guò)Xdebug來(lái)觀察變量的信息,他們指的都是同一個(gè)內(nèi)存地址,是引用。
$a = 'chris'.time();$b = '青玄';$c = $a;xdebug_debug_zval('a');xdebug_debug_zval('b');//a:(refcount=2, is_ref=0)string 'chris1614780283' (length=15)
 //b:(interned, is_ref=0)string '青玄' (length=6) //存在了靜態(tài)區(qū)我們通過(guò)Xdebug來(lái)觀察變量的信息,這時(shí)$b的值已經(jīng)發(fā)生了變化,這時(shí)候,才會(huì)使用新的內(nèi)存空間,$a的引用次數(shù)-1。

引用計(jì)數(shù)

每個(gè)php變量存在一個(gè)叫”zval”的變量容器中。一個(gè)zval變量容器,除了包含變量的類型和值,還包括兩個(gè)字節(jié)的額外信息。第一個(gè)是”is_ref”,是個(gè)bool值,用來(lái)標(biāo)識(shí)這個(gè)變量是否是屬于引用集合(reference set)。通過(guò)這個(gè)字節(jié),php引擎才能把普通變量和引用變量區(qū)分開(kāi)來(lái),由于php允許用戶通過(guò)使用&來(lái)使用自定義引用,zval變量容器中還有一個(gè)內(nèi)部引用計(jì)數(shù)機(jī)制,來(lái)優(yōu)化內(nèi)存使用。第二個(gè)額外字節(jié)是”refcount”,用以表示指向這個(gè)zval變量容器的變量(也稱符號(hào)即symbol)個(gè)數(shù)。

官方文檔的描述

簡(jiǎn)單來(lái)說(shuō),就是給變量引用的次數(shù)進(jìn)行計(jì)算,當(dāng)計(jì)數(shù)refcount不等于0時(shí),說(shuō)明這個(gè)變量已經(jīng)被引用,不能直接被回收,否則可以直接回收,用代碼來(lái)看看把

$a='chris'.time();$b=$a;$c=$a; $b='青玄';unset($c);xdebug_debug_zval('a');//a:(refcount=1, is_ref=0)string 'chris1614780526'(length=5)//我們可以看到,刪除$c,并不能把$a刪除,因?yàn)閞efcount=1

內(nèi)存泄漏

function a(){class A {
   public $ref;
   public $name;

   public function __construct($name) { $this->name = $name; echo($this->name.'->__construct();'.PHP_EOL);
   }

   public function __destruct() {  echo($this->name.'->__destruct();'.PHP_EOL);
   }}$a1 = new A('$a1');$a2 = new A('$a2');$a3 = new A('$3');$a1->ref = $a2;$a2->ref = $a1;unset($a1);unset($a2);echo('exit(1);'.PHP_EOL);}a();echo('exit(2);'.PHP_EOL);

當(dāng)$a1和$a2的屬性互相引用時(shí),unset($a1,$a2) 只能刪除變量的引用,卻沒(méi)有真正的刪除類的變量,這是為什么呢?

首先,類的實(shí)例化變量分為2個(gè)步驟

1:開(kāi)辟類存儲(chǔ)空間,用于存儲(chǔ)類數(shù)據(jù)

2:實(shí)例化一個(gè)變量,類型為class,值指向類存儲(chǔ)空間

當(dāng)給變量賦值成功后,類的引用計(jì)數(shù)為1,同時(shí),a1->ref指向了a2,導(dǎo)致a2類引用計(jì)數(shù)增加1,同時(shí)a1類被a2->ref引用,a1引用計(jì)數(shù)增加1

當(dāng)unset時(shí),只會(huì)刪除類的變量引用,也就是-1,但是該類其實(shí)還存在了一次引用(類的互相引用),

這將造成這2個(gè)類內(nèi)存永遠(yuǎn)無(wú)法釋放,直到被gc機(jī)制循環(huán)查找回收,或腳本終止回收(域結(jié)束無(wú)法回收).

PHP作用域的生命周期和變量回收

每個(gè)方法/函數(shù)都作為一個(gè)作用域,當(dāng)運(yùn)行完該作用域時(shí),將會(huì)回收作用域內(nèi)的所有變量,全局變量只有在腳本結(jié)束后才會(huì)回收。

我們可以通過(guò)以下方式來(lái)手動(dòng)回收:

  • unset() : unset的回收原理其實(shí)就是引用計(jì)數(shù)-1,當(dāng)引用計(jì)數(shù)-1之后為0時(shí),將會(huì)直接回收該變量,否則不做操作(這就是上面內(nèi)存泄漏的原因,引用計(jì)數(shù)-1并沒(méi)有等于0)。

  • 賦值為null :=null和unset($a),作用其實(shí)都為一致,null將變量值賦值為null,原先的變量值引用計(jì)數(shù)-1,而unset是將變量名從php底層變量表中清理,并將變量值引用計(jì)數(shù)-1,唯一的區(qū)別在于,=null,變量名還存在,而unset之后,該變量就沒(méi)了。

  • 變量覆蓋回收:通過(guò)給變量賦值其他值(例如null)進(jìn)行回收,但是從程序的內(nèi)存占用來(lái)說(shuō),覆蓋變量并不是意義上的內(nèi)存回收,只是將變量的內(nèi)存修改為了其他值.內(nèi)存不會(huì)直接清空。

  • gc_collect_cycles :強(qiáng)制執(zhí)行周期回收,在PHP執(zhí)行中,一旦根緩沖區(qū)滿了或者調(diào)用gc_collect_cycles() 函數(shù)時(shí),就會(huì)執(zhí)行垃圾回收

另外:為避免不得不檢查所有引用計(jì)數(shù)可能減少的垃圾周期,PHP會(huì)有算法把疑似垃圾的變量,放在根緩沖區(qū)(root buffer)中,在根緩沖區(qū)滿了的時(shí)候,也會(huì)對(duì)垃圾緩沖區(qū)進(jìn)行一次回收。

到此,相信大家對(duì)“PHP的垃圾回收機(jī)制相關(guān)知識(shí)點(diǎn)整理”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI