這篇文章將為大家詳細(xì)講解有關(guān)PHP7垃圾回收機(jī)制的案例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
專(zhuān)注于為中小企業(yè)提供網(wǎng)站建設(shè)、成都網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)貴溪免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。垃圾回收:
簡(jiǎn)稱(chēng)GC。顧名思義,就是廢物重利用的意思。
說(shuō)垃圾回收機(jī)制之前,先接觸一下內(nèi)存泄漏。
內(nèi)存泄漏:
某大神重口味充滿畫(huà)面感的形象解釋?zhuān)?/p>
大概意思就是申請(qǐng)了一塊地兒拉了會(huì)兒屎,拉完后不收拾,那么那塊兒地就算是糟蹋了,地越用越少,最后一地全是屎。說(shuō)到底一句,用了記得還。一定程度上說(shuō),垃圾回收機(jī)制就是用來(lái)擦屁股的。
c語(yǔ)言垃圾回收機(jī)制:
如果用過(guò)C語(yǔ)言,那么申請(qǐng)內(nèi)存的方式是malloc或者是calloc,然后你用完這個(gè)內(nèi)存后,一定不要忘了用free函數(shù)去釋放掉,這就是手動(dòng)垃圾回收,一般都是大神用這種方式。
php的自動(dòng)垃圾回收機(jī)制是怎樣的呢?
這個(gè)問(wèn)題我們先這么想,我們都知道php是C語(yǔ)言實(shí)現(xiàn)的。你想想如何用C語(yǔ)言實(shí)現(xiàn)對(duì)一個(gè)變量的統(tǒng)計(jì)以及釋放。C語(yǔ)言是如何實(shí)現(xiàn)一個(gè)變量,從聲明開(kāi)始到最后沒(méi)人用了,就把這個(gè)變量所占的內(nèi)存給釋放掉(被垃圾回收)。
PHP進(jìn)行內(nèi)存管理的核心算法一共兩項(xiàng):
一是引用計(jì)數(shù),二是寫(xiě)時(shí)拷貝
聲明一個(gè)PHP變量的時(shí)候,C語(yǔ)言就在底層生成一個(gè)叫做zval的struct(結(jié)構(gòu)體),如下:
zval { string "a" //變量的名字是a value zend_value //變量的值,聯(lián)合體 type string //變量是字符串類(lèi)型 }
zval struct結(jié)構(gòu)體
(1)保存php $a的變量名
(2)php $a的變量類(lèi)型
(3)php變量$a的zend_value聯(lián)合體
如果給變量賦值了,比如“hello world”,那么C語(yǔ)言就在底層再生成一個(gè)叫做zend_value的union(聯(lián)合體)
zend_value { string "hello world" //值的內(nèi)容 refcount 1 //引用計(jì)數(shù) }
zend_value的union(聯(lián)合體)
(1)保存php $a的變量的值hello world
(2)記錄php $a變量引用次數(shù)
看到 zval struct結(jié)構(gòu)體和zend_value,如果面試官問(wèn)你php變量為什么能夠保存字符串"123"也能保存數(shù)字123,你知道該怎么回答了吧?就答出重點(diǎn)zval中有該變量的類(lèi)型,當(dāng)是字符串123的時(shí)候,type就是string,此時(shí)value指向“123”;當(dāng)是整數(shù)123的時(shí)候,zval的type為int,value為123。
何為引用計(jì)數(shù)?
代碼實(shí)戰(zhàn)解析php變量引用計(jì)數(shù)
$a = 'hello,world'; echo xdebug_debug_zval( 'a');//refcount=1 $b = $a; echo xdebug_debug_zval( 'a'); //$b引用$a,故變量a,refcount=2 $c = $a; echo xdebug_debug_zval( 'a'); //$c引用$a,故變量a,refcount=3 unset( $c ); echo xdebug_debug_zval( 'a');//刪除了$c的引用,故變量a,refcount=2
運(yùn)行結(jié)果:
a:
(refcount=1, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=2, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=3, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=2, is_ref=0)string 'hello,world' (length=11)
何為拷貝復(fù)制?
$a = 'hello'; $b = $a;//$a賦值給$b的時(shí)候,$a的值并沒(méi)有真的復(fù)制了一份 echo xdebug_debug_zval( 'a');//$a的引用計(jì)數(shù)為2 $a = 'world';//當(dāng)我們修改$a的值為123的時(shí)候,這個(gè)時(shí)候就不得已進(jìn)行復(fù)制,避免$b的值和$a的一樣 echo xdebug_debug_zval( 'a');///$a的引用計(jì)數(shù)為1
運(yùn)行結(jié)果:
a:
(refcount=2, is_ref=0)string 'hello' (length=5)
a:
(refcount=1, is_ref=0)string 'world' (length=5)
其實(shí),當(dāng)你把$a賦值給$b的時(shí)候,$a的值并沒(méi)有真的復(fù)制了一份,這樣是對(duì)內(nèi)存的極度不尊重,也是對(duì)時(shí)間復(fù)雜度的極度不尊重,計(jì)算機(jī)僅僅是將$b指向了$a的值而已,這就叫多快好省。那么,什么時(shí)候真正的發(fā)生復(fù)制呢?就是當(dāng)我們修改$a的值為123的時(shí)候,這個(gè)時(shí)候就不得已進(jìn)行復(fù)制,避免$b的值和$a的一樣。
通過(guò)簡(jiǎn)單的案例解釋清楚了兩個(gè)要點(diǎn):引用計(jì)數(shù)和寫(xiě)時(shí)拷貝。
垃圾回收機(jī)制:
當(dāng)一個(gè)zval在被unset的時(shí)候、或者從一個(gè)函數(shù)中運(yùn)行完畢出來(lái)(就是局部變量)的時(shí)候等等很多地方,都會(huì)產(chǎn)生zval與zend_value發(fā)生斷開(kāi)的行為,這個(gè)時(shí)候zend引擎需要檢測(cè)的就是zend_value的refcount是否為0,如果為0,則直接KO free空出內(nèi)容來(lái)。如果zend_value的recount不為0,這個(gè)value不能被釋放,但是也不代表這個(gè)zend_value是清白的,因?yàn)榇藌end_value依然可能是個(gè)垃圾。
(1)當(dāng)php變量$a的refcount=0時(shí),變量$a就會(huì)被垃圾回收
(2)當(dāng)php變量$a的refcount>0時(shí),變量$a但也可能被認(rèn)為是垃圾
什么樣的情況會(huì)導(dǎo)致zend_value的refcount不為0,但是這個(gè)zend_value卻是個(gè)垃圾呢?
$arr = [ 1 ]; $arr[] = &$arr; unset( $arr );
這種情況下,zend_value不會(huì)能釋放,但也不能放過(guò)它,不然一定會(huì)產(chǎn)生內(nèi)存泄漏,所以這會(huì)兒zend_value會(huì)被扔到一個(gè)叫做垃圾回收堆中,然后zend引擎會(huì)依次對(duì)垃圾回收堆中的這些zend_value進(jìn)行二次檢測(cè),檢測(cè)是不是由于上述兩種情況造成的refcount為1但是自身卻確實(shí)沒(méi)有人再用了,如果一旦確定是上述兩種情況造成的,那么就會(huì)將zend_value徹底抹掉釋放內(nèi)存。
垃圾回收發(fā)生在什么時(shí)候?
有些同學(xué)可能有疑問(wèn),就是php不是運(yùn)行一次就銷(xiāo)毀了嗎,我要gc有何用?并不是的,首先當(dāng)一次fpm運(yùn)行完畢后,最后一定還有g(shù)c的,這個(gè)銷(xiāo)毀就是gc;其次是,內(nèi)存都是即用即釋放的,而不是攢著非得到最后,你想想一個(gè)典型的場(chǎng)景,你的控制器里的某個(gè)方法里用了一個(gè)函數(shù),函數(shù)需要一個(gè)巨大的數(shù)組參數(shù),然后函數(shù)還需要修改這個(gè)巨大的數(shù)組參數(shù),你們應(yīng)該是函數(shù)的運(yùn)行范圍里面修改這個(gè)數(shù)組,所以此時(shí)會(huì)發(fā)生寫(xiě)時(shí)拷貝了,當(dāng)函數(shù)運(yùn)行完畢后,就得趕緊釋放掉這塊兒內(nèi)存以供給其他進(jìn)程使用,而不是非得等到本地fpm request徹底完成后才銷(xiāo)毀。
(1)fpm運(yùn)行完畢后,最后一定會(huì)gc的
(2)運(yùn)行過(guò)程中,也會(huì)gc的,內(nèi)存都是即用即釋放的,而不是攢著非得到最后gc
關(guān)于PHP7垃圾回收機(jī)制的案例分析就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
分享名稱(chēng):PHP7垃圾回收機(jī)制的案例分析-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)URL:http://jinyejixie.com/article36/diphpg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、用戶體驗(yàn)、App開(kāi)發(fā)、Google、全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容