日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
深入講解PHP垃圾回收及內(nèi)存管理相關(guān)內(nèi)容

本文將要講述 PHP 發(fā)展歷程中的垃圾回收及內(nèi)存管理相關(guān)內(nèi)容。

創(chuàng)新互聯(lián)建站長(zhǎng)期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為屏邊企業(yè)提供專業(yè)的網(wǎng)站制作、成都網(wǎng)站制作,屏邊網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

在 PHP 5.2 及以前的版本中,PHP 的垃圾回收采用的是 引用計(jì)數(shù) 算法。

引用計(jì)數(shù)基礎(chǔ)知識(shí)

引用計(jì)數(shù)基礎(chǔ)知識(shí)

php 的變量存儲(chǔ)在「zval」變量容器(數(shù)據(jù)結(jié)構(gòu))中,「zval」屬性包含如下信息:

  • 當(dāng)前變量的數(shù)據(jù)類型;
  • 當(dāng)前變量的值;
  • 用于標(biāo)識(shí)變量是否為引用傳遞的 is_ref 布爾類型標(biāo)識(shí);
  • 指向該「zval」變量容器的變量個(gè)數(shù)的 refcount 標(biāo)識(shí)符(即這個(gè) zval 被引用的次數(shù),注意這里的引用不是指引用傳值,注意區(qū)分)。

當(dāng)一個(gè)變量被賦值時(shí),就會(huì)生成一個(gè)對(duì)應(yīng)的「zavl」變量容器?!就扑]學(xué)習(xí):PHP視頻教程】

查看變量 zval 容器信息

要查看變量的「zval」容器信息(即查看變量的 is_ref 和 refcount),可以使用 XDebug 調(diào)試工具的 xdebug_debug_zval() 函數(shù)。

安裝 XDebug 擴(kuò)展插件的方法可以查看 這個(gè)教程(https://github.com/huliuqing/phpnotes/issues/58),有關(guān)XDebug 使用方法請(qǐng)閱讀 官方文檔(https://xdebug.org/docs/)。

假設(shè),我們已經(jīng)成功安裝好 XDebug 工具,現(xiàn)在就可以來(lái)對(duì)變量進(jìn)行調(diào)試了。

  • 查看普通變量的 zval 信息

如果我們的 PHP 語(yǔ)句只是對(duì)變量進(jìn)行簡(jiǎn)單賦值時(shí),is_ref 標(biāo)識(shí)值為 0,refcount 值為 1;若將這個(gè)變量作為值賦值給另一個(gè)變量時(shí),則增加 zval 變量容器的 refcount 計(jì)數(shù);同理,銷毀(unset)變量時(shí),「refcount」相應(yīng)的減去 1。

請(qǐng)看下面的示例:


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

通過(guò)前面的簡(jiǎn)單變量的 zval 信息我們知道 $copy$name 共用 zval 變量容器(內(nèi)存),然后通過(guò) refcount 來(lái)表示當(dāng)前這個(gè) zval 被多少個(gè)變量使用。

看個(gè)實(shí)例:


注意到?jīng)]有,當(dāng)將值 liugongzi handsome 賦值給變量 $copy 時(shí),name 和 copy 的 refcount 值都變成了 1,在這個(gè)過(guò)程中發(fā)生以下幾個(gè)操作:

  • 將 $copy 從 $name 的 zval(內(nèi)從)中分離出來(lái)(即復(fù)制);
  • 將 $name 的 refcount 減去 1;
  • 對(duì) $copy 的 zval 進(jìn)行修改(重新賦值和修改 refcount);

這里只是簡(jiǎn)單對(duì)「寫(xiě)時(shí)復(fù)制」進(jìn)行介紹,感興趣的朋友可以閱讀文末給出的參考資料進(jìn)行更加深入的研究。

  • 查看引用傳遞變量的 zval 信息

引用傳值(&)的「引用計(jì)數(shù)」規(guī)則同普通賦值語(yǔ)句一樣,只是 is_ref 標(biāo)識(shí)的值為 1 表示該變量是引用傳值類型。

我們現(xiàn)在來(lái)看看引用傳值的示例:


  • 復(fù)合類型的引用計(jì)數(shù)

與標(biāo)量類型(整型、浮點(diǎn)型、布爾型等)不同,數(shù)組(array)和對(duì)象(object)這種符合類型的引用計(jì)數(shù)規(guī)則會(huì)稍復(fù)雜一些。

為了更好的說(shuō)明,還是先看看數(shù)組的引用計(jì)數(shù)示例:

$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );

// a:
// (refcount=1, is_ref=0)
// array (size=2)
//  'meaning' => (refcount=1, is_ref=0)string 'life' (length=4)
//  'number' => (refcount=1, is_ref=0)int 42

上面的引用計(jì)數(shù)示意圖如下:

從圖中我們發(fā)現(xiàn)復(fù)合類型的引用計(jì)數(shù)規(guī)則基本上同標(biāo)量的計(jì)數(shù)規(guī)則一樣,就給出的示例來(lái)說(shuō),PHP 會(huì)創(chuàng)建 3 個(gè) zval 變量容器,一個(gè)用于存儲(chǔ)數(shù)組本身,另外兩個(gè)用于存儲(chǔ)數(shù)組中的元素。

添加一個(gè)已經(jīng)存在的元素到數(shù)組中時(shí),它的引用計(jì)數(shù)器 refcount 會(huì)增加 1。

$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
$a['life'] = $a['meaning'];
xdebug_debug_zval( 'a' );

// a:
// (refcount=1, is_ref=0)
// array (size=3)
//  'meaning' => (refcount=2, is_ref=0)string 'life' (length=4)
//  'number' => (refcount=0, is_ref=0)int 42
//  'life' => (refcount=2, is_ref=0)string 'life' (length=4)

大致示意圖如下:

  • 內(nèi)存泄露

雖然,復(fù)合類型的引用計(jì)數(shù)規(guī)則同標(biāo)量類型大致相同,但是如果引用的值為變量自身(即循環(huán)應(yīng)用),在處理不當(dāng)時(shí),就有可能會(huì)造成內(nèi)存泄露的問(wèn)題。

讓我們來(lái)看看下面這個(gè)對(duì)數(shù)組進(jìn)行引用傳值的示例:


從內(nèi)存占用結(jié)果上看,雖然我們執(zhí)行了 unset($a) 方法來(lái)銷毀 $a 數(shù)組,但內(nèi)存并沒(méi)有被回收,整個(gè)處理過(guò)程的示意圖如下:

可以看到對(duì)于這塊內(nèi)存,再也沒(méi)有符合表(變量)指向了,所以 PHP 無(wú)法完成內(nèi)存回收,官方給出的解釋如下:

簡(jiǎn)單來(lái)說(shuō)就是「引用計(jì)數(shù)」算法無(wú)法檢測(cè)并釋放循環(huán)引用所使用的內(nèi)存,最終導(dǎo)致內(nèi)存泄露。

引用計(jì)數(shù)系統(tǒng)的同步周期回收

由于引用計(jì)數(shù)算法存在無(wú)法回收循環(huán)應(yīng)用導(dǎo)致的內(nèi)存泄露問(wèn)題,在 PHP 5.3 之后對(duì)內(nèi)存回收的實(shí)現(xiàn)做了優(yōu)化,通過(guò)采用 引用計(jì)數(shù)系統(tǒng)的同步周期回收 算法實(shí)現(xiàn)內(nèi)存管理。引用計(jì)數(shù)系統(tǒng)的同步周期回收算法是一個(gè)改良版本的引用計(jì)數(shù)算法,它在引用基礎(chǔ)上做出了如下幾個(gè)方面的增強(qiáng):

  • 引入了可能根(possible root)的概念:通過(guò)引用計(jì)數(shù)相關(guān)學(xué)習(xí),我們知道如果一個(gè)變量(zval)被引用,要么是被全局符號(hào)表中的符號(hào)引用(即變量),要么被復(fù)雜類型(如數(shù)組)的 zval 中的符號(hào)(數(shù)組的元素)引用,那么這個(gè) zval 變量容器就是「可能根」。
  • 引入根緩沖區(qū)(root buffer)的概念:根緩沖區(qū)用于存放所有「可能根」,它是固定大小的,默認(rèn)可存 10000 個(gè)可能根,如需修改可以通過(guò)修改 PHP 源碼文件 Zend/zend_gc.c 中的常量 GC_ROOT_BUFFER_MAX_ENTRIES,再重新編譯。
  • 回收周期:當(dāng)緩沖區(qū)滿時(shí),對(duì)緩沖區(qū)中的所有可能根進(jìn)行垃圾回收處理。

下圖(來(lái)自 PHP 手冊(cè)),展示了新的回收算法執(zhí)行過(guò)程:

引用計(jì)數(shù)系統(tǒng)的同步周期回收過(guò)程

  1. 緩沖區(qū)(紫色框部分,稱為疑似垃圾),存儲(chǔ)所有可能根(步驟 A);
  2. 采用深度優(yōu)先算法遍歷「根緩沖區(qū)」中所有的「可能根(即 zval 遍歷容器)」,并對(duì)每個(gè) zval 的 refcount 減 1,為了避免遍歷時(shí)對(duì)同一個(gè) zval 多次減 1(因?yàn)椴煌母赡鼙闅v到同一個(gè) zval)將這個(gè) zvel 標(biāo)記為「已減」(步驟 B);
  3. 再次采用深度優(yōu)先遍歷算法遍歷「可能根 zval」。當(dāng) zval 的 refcount 值不為 0 時(shí),對(duì)其加 1,否則保持為 0。并請(qǐng)已遍歷的 zval 變量容器標(biāo)記為「已恢復(fù)」(即步驟 B 的逆運(yùn)算)。那些 zval 的 refcount 值為 0 (藍(lán)色框標(biāo)記)的就是應(yīng)該被回收的變量(步驟 C);
  4. 刪除所有 refcount 為 0 的可能根(步驟 D)。

整個(gè)過(guò)程為:

采用深度優(yōu)先算法執(zhí)行:默認(rèn)刪除 > 模擬恢復(fù) > 執(zhí)行刪除 達(dá)到內(nèi)存回收的目的。

優(yōu)化后的引用計(jì)數(shù)算法優(yōu)勢(shì)

  • 將內(nèi)存泄露控制在閥值內(nèi),這個(gè)由緩存區(qū)實(shí)現(xiàn),達(dá)到緩沖區(qū)大小執(zhí)行新一輪垃圾回收;
  • 提升了垃圾回收性能,不是每次 refcount 減 1 都執(zhí)行回收處理,而是等到根緩沖區(qū)滿時(shí)才開(kāi)始執(zhí)行垃圾回收。

你可以從 PHP 手冊(cè) 的回收周期 了解更多,也可以閱讀文末給出的參考資料。

PHP 7 的內(nèi)存管理

PHP 5 中 zval 實(shí)現(xiàn)上的主要問(wèn)題:

  • zval 總是單獨(dú) 從堆中分配內(nèi)存;
  • zval 總是存儲(chǔ)引用計(jì)數(shù)和循環(huán)回收 的信息,即使是整型(bool / null)這種可能并不需要此類信息的數(shù)據(jù);
  • 在使用對(duì)象或者資源時(shí),直接引用會(huì)導(dǎo)致兩次計(jì)數(shù);
  • 某些間接訪問(wèn)需要一個(gè)更好的處理方式。比如現(xiàn)在訪問(wèn)存儲(chǔ)在變量中的對(duì)象間接使用了四個(gè)指針(指針鏈的長(zhǎng)度為四);
  • 直接計(jì)數(shù)也就意味著數(shù)值只能在 zval 之間共享。如果想在 zval 和 hashtable key 之間共享一個(gè)字符串就不行(除非 hashtable key 也是 zval)。

PHP 7 中的 zval 數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的調(diào)整:

這種實(shí)現(xiàn)的優(yōu)勢(shì):

  • 簡(jiǎn)單數(shù)據(jù)類型不需要單獨(dú)分配內(nèi)存,也不需要計(jì)數(shù);
  • 不會(huì)再有兩次計(jì)數(shù)的情況。在對(duì)象中,只有對(duì)象自身存儲(chǔ)的計(jì)數(shù)是有效的;
  • 由于現(xiàn)在計(jì)數(shù)由數(shù)值自身存儲(chǔ)(PHP 有 zval 變量容器存儲(chǔ)),所以也就可以和非 zval 結(jié)構(gòu)的數(shù)據(jù)共享,比如 zval 和 hashtable key 之間;
  • 間接訪問(wèn)需要的指針數(shù)減少了。

網(wǎng)站名稱:深入講解PHP垃圾回收及內(nèi)存管理相關(guān)內(nèi)容
URL標(biāo)題:http://www.5511xx.com/article/dpcgeio.html