亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

PHP中垃圾回收與內存管理的詳細分析

2020-03-22 17:38:55
字體:
來源:轉載
供稿:網友
本篇文章給大家帶來的內容是關于PHP中垃圾回收與內存管理的詳細分析,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

引用計數

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

引用計數基礎知識

php 的變量存儲在「zval」變量容器(數據結構)中,「zval」屬性包含如下信息:

當前變量的數據類型;

當前變量的值;

用于標識變量是否為引用傳遞的 is_ref 布爾類型標識;

指向該「zval」變量容器的變量個數的 refcount 標識符(即這個 zval 被引用的次數,注意這里的引用不是指引用傳值,注意區分)。

當一個變量被賦值時,就會生成一個對應的「zavl」變量容器。

查看變量 zval 容器信息

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

安裝 XDebug 擴展插件的方法可以查看 這個教程,有關XDebug 使用方法請閱讀 官方文檔。

假設,我們已經成功安裝好 XDebug 工具,現在就可以來對變量進行調試了。

查看普通變量的 zval 信息

如果我們的 PHP 語句只是對變量進行簡單賦值時,is_ref 標識值為 0,refcount 值為 1;若將這個變量作為值賦值給另一個變量時,則增加 zval 變量容器的 refcount 計數;同理,銷毀(unset)變量時,「refcount」相應的減去 1。

請看下面的示例:

 ?php// 變量賦值時,refcount 值等于 1$name = liugongzi xdebug_debug_zval( name // (refcount=1, is_ref=0)string liugongzi (length=9)// $name 作為值賦值給另一個變量, refcount 值增加 1$copy = $name;xdebug_debug_zval( name // (refcount=2, is_ref=0)string liugongzi (length=9)// 銷毀變量,refcount 值減掉 1unset($copy);xdebug_debug_zval( name // (refcount=1, is_ref=0)string liugongzi (length=9)

寫時復制

寫時復制(CopyWrite:COW),簡單描述為:如果通過賦值的方式賦值給變量時不會申請新內存來存放新變量所保存的值,而是簡單的通過一個計數器來共用內存,只有在其中的一個引用指向變量的值發生變化時,才申請新空間來保存值內容以減少對內存的占用。 - TPIP 寫時復制

通過前面的簡單變量的 zval 信息我們知道 dollar;copy 和 dollar;name 共用 zval 變量容器(內存),然后通過 refcount 來表示當前這個 zval 被多少個變量使用。

看個實例:

 ?php$name = liugongzi xdebug_debug_zval( name // name: (refcount=1, is_ref=0)string liugongzi (length=9)$copy = $name;xdebug_debug_zval( name // name: (refcount=2, is_ref=0)string liugongzi (length=9)// 將新的值賦值給變量 $copy$copy = liugongzi handsome xdebug_debug_zval( name // name: (refcount=1, is_ref=0)string liugongzi (length=9)xdebug_debug_zval( copy // copy: (refcount=1, is_ref=0)= liugongzi handsome 

注意到沒有,當將值 liugongzi handsome 賦值給變量 dollar;copy 時,name 和 copy 的 refcount 值都變成了 1,在這個過程中發生以下幾個操作:

將 dollar;copy 從 dollar;name 的 zval(內從)中分離出來(即復制);

將 dollar;name 的 refcount 減去 1;

對 dollar;copy 的 zval 進行修改(重新賦值和修改 refcount);

這里只是簡單對「寫時復制」進行介紹,感興趣的朋友可以閱讀文末給出的參考資料進行更加深入的研究。

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

引用傳值( )的「引用計數」規則同普通賦值語句一樣,只是 is_ref 標識的值為 1 表示該變量是引用傳值類型。

我們現在來看看引用傳值的示例:

 ?php$age = liugongzi xdebug_debug_zval( age // (refcount=1, is_ref=0)string liugongzi (length=9)$copy = $age;xdebug_debug_zval( age // (refcount=2, is_ref=1)string liugongzi (length=9)unset($copy);xdebug_debug_zval( age // (refcount=1, is_ref=1)string liugongzi (length=9)

復合類型的引用計數

與標量類型(整型、浮點型、布爾型等)不同,數組(array)和對象(object)這種符合類型的引用計數規則會稍復雜一些。

為了更好的說明,還是先看看數組的引用計數示例:

$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

上面的引用計數示意圖如下:

1501872237-5b6b9bfa93428_articlex.png

從圖中我們發現復合類型的引用計數規則基本上同標量的計數規則一樣,就給出的示例來說,PHP 會創建 3 個 zval 變量容器,一個用于存儲數組本身,另外兩個用于存儲數組中的元素。

添加一個已經存在的元素到數組中時,它的引用計數器 refcount 會增加 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)

大致示意圖如下:

953995291-5b6b9bfa9344f_articlex.png

內存泄露

雖然,復合類型的引用計數規則同標量類型大致相同,但是如果引用的值為變量自身(即循環應用),在處理不當時,就有可能會造成內存泄露的問題。

讓我們來看看下面這個對數組進行引用傳值的示例:

 ?php// @link http://php.net/manual/zh/function.memory-get-usage.php#96280function convert($size) $unit=array( b , kb , mb , gb , tb , pb  return @round($size/pow(1024,($i=floor(log($size,1024)))),2). .$unit[$i];// 注意:有用的地方從這里開始$memory = memory_get_usage();$a = array( one // 引用自身(循環引用)$a[] = xdebug_debug_zval( a var_dump(convert(memory_get_usage() - $memory)); // 296 bunset($a); // 刪除變量 $a,由于 $a 中的元素引用了自身(循環引用)最終導致 $a 所使用的內存無法被回收var_dump(convert(memory_get_usage() - $memory)); // 568 b

從內存占用結果上看,雖然我們執行了 unset( dollar;a) 方法來銷毀 dollar;a 數組,但內存并沒有被回收,整個處理過程的示意圖如下:

1792250044-5abcb89a91c96_articlex.png

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

盡管不再有某個作用域中的任何符號指向這個結構 (就是變量容器),由于數組元素 “1” 仍然指向數組本身,所以這個容器不能被清除 。因為沒有另外的符號指向它,用戶沒有辦法清除這個結構,結果就會導致內存泄漏。慶幸的是,php 將在腳本執行結束時清除這個數據結構,但是在 php清除之前,將耗費不少內存。如果你要實現分析算法,或者要做其他像一個子元素指向它的父元素這樣的事情,這種情況就會經常發生。當然,同樣的情況也會發生在對象上,實際上對象更有可能出現這種情況,因為對象總是隱式的被引用。

簡單來說就是「引用計數」算法無法檢測并釋放循環引用所使用的內存,最終導致內存泄露。

引用計數系統的同步周期回收

由于引用計數算法存在無法回收循環應用導致的內存泄露問題,在 PHP 5.3 之后對內存回收的實現做了優化,通過采用 引用計數系統的同步周期回收 算法實現內存管理。引用計數系統的同步周期回收算法是一個改良版本的引用計數算法,它在引用基礎上做出了如下幾個方面的增強:

引入了可能根(possible root)的概念:通過引用計數相關學習,我們知道如果一個變量(zval)被引用,要么是被全局符號表中的符號引用(即變量),要么被復雜類型(如數組)的 zval 中的符號(數組的元素)引用,那么這個 zval 變量容器就是「可能根」。

引入根緩沖區(root buffer)的概念:根緩沖區用于存放所有「可能根」,它是固定大小的,默認可存 10000 個可能根,如需修改可以通過修改 PHP 源碼文件 Zend/zend_gc.c 中的常量 GC_ROOT_BUFFER_MAX_ENTRIES,再重新編譯。

回收周期:當緩沖區滿時,對緩沖區中的所有可能根進行垃圾回收處理。

下圖(來自 PHP 手冊),展示了新的回收算法執行過程:

2803415693-5b6b9bfaf295a_articlex.png

引用計數系統的同步周期回收過程

緩沖區(紫色框部分,稱為疑似垃圾),存儲所有可能根(步驟 A);

采用深度優先算法遍歷「根緩沖區」中所有的「可能根(即 zval 遍歷容器)」,并對每個 zval 的 refcount 減 1,為了避免遍歷時對同一個 zval 多次減 1(因為不同的根可能遍歷到同一個 zval)將這個 zvel 標記為「已減」(步驟 B);

再次采用深度優先遍歷算法遍歷「可能根 zval」。當 zval 的 refcount 值不為 0 時,對其加 1,否則保持為 0。并請已遍歷的 zval 變量容器標記為「已恢復」(即步驟 B 的逆運算)。那些 zval 的 refcount 值為 0 (藍色框標記)的就是應該被回收的變量(步驟 C);

刪除所有 refcount 為 0 的可能根(步驟 D)。

整個過程為:

采用深度優先算法執行:默認刪除 模擬恢復 執行刪除 達到內存回收的目的。

優化后的引用計數算法優勢

將內存泄露控制在閥值內,這個由緩存區實現,達到緩沖區大小執行新一輪垃圾回收;

提升了垃圾回收性能,不是每次 refcount 減 1 都執行回收處理,而是等到根緩沖區滿時才開始執行垃圾回收。

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

PHP 7 的內存管理

PHP 5 中 zval 實現上的主要問題:

zval 總是單獨 從堆中分配內存;

zval 總是存儲引用計數和循環回收 的信息,即使是整型(bool / null)這種可能并不需要此類信息的數據;

在使用對象或者資源時,直接引用會導致兩次計數;

某些間接訪問需要一個更好的處理方式。比如現在訪問存儲在變量中的對象間接使用了四個指針(指針鏈的長度為四);

直接計數也就意味著數值只能在 zval 之間共享。如果想在 zval 和 hashtable key 之間共享一個字符串就不行(除非 hashtable key 也是 zval)。

PHP 7 中的 zval 數據結構實現的調整:

最基礎的變化就是 zval 需要的內存 不再是單獨從堆上分配,不再由 zval 存儲引用計數。
復雜數據類型(比如字符串、數組和對象)的引用計數由其自身來存儲。

這種實現的優勢:

簡單數據類型不需要單獨分配內存,也不需要計數;

不會再有兩次計數的情況。在對象中,只有對象自身存儲的計數是有效的;

由于現在計數由數值自身存儲(PHP 有 zval 變量容器存儲),所以也就可以和非 zval 結構的數據共享,比如 zval 和 hashtable key 之間;

間接訪問需要的指針數減少了。

相關文章推薦:

PHP之腳本的內存管理和垃圾回收 - 個人文章 思否

跟我學習javascript的垃圾回收機制與內存管理_javascript技巧

垃圾回收 PHP垃圾回收機制簡單說明

以上就是PHP中垃圾回收與內存管理的詳細分析的詳細內容,PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品国产精品亚洲| 国产精品视频最多的网站| 久久综合国产精品台湾中文娱乐网| 国产精品第一第二| 欧美乱大交做爰xxxⅹ性3| 日韩在线观看你懂的| 亚洲91精品在线| 亚洲欧美成人在线| 亚洲激情视频在线观看| 亚洲乱码一区二区| 国产日韩欧美中文| 国产精品久久久久久一区二区| 亚洲欧美国产精品久久久久久久| 亚洲少妇激情视频| 97国产一区二区精品久久呦| 欧美丝袜一区二区三区| 欧美精品在线网站| 久久国产精品网站| 欧美日韩亚洲视频一区| 国产精品久久精品| 亚洲成人精品在线| 欧美激情欧美激情在线五月| 国产97在线播放| 2019亚洲日韩新视频| 国产日韩在线观看av| 亚洲国语精品自产拍在线观看| 亚洲精品久久久久国产| 欧美激情图片区| 97精品伊人久久久大香线蕉| 亚洲视屏在线播放| 97香蕉久久夜色精品国产| 精品国产一区二区三区久久狼5月| 欧洲永久精品大片ww免费漫画| 伊人久久大香线蕉av一区二区| 欧美日韩亚洲一区二| 中文字幕久久亚洲| 欧美俄罗斯乱妇| 欧美日韩综合视频| 国产亚洲欧美aaaa| 不卡中文字幕av| 国内精品国产三级国产在线专| 91香蕉嫩草神马影院在线观看| 精品人伦一区二区三区蜜桃免费| 久久成人在线视频| 亚洲无限av看| 91国语精品自产拍在线观看性色| 69av在线播放| 中文日韩电影网站| 欧美不卡视频一区发布| 国产精品久久精品| 亚洲欧美一区二区三区久久| 欧美www在线| 亚洲夜晚福利在线观看| 亚洲高清不卡av| 亚洲欧美一区二区精品久久久| 亚洲人成网站999久久久综合| 国产精品欧美久久久| 日韩电影中文字幕av| 51精品国产黑色丝袜高跟鞋| 国产亚洲精品久久| 国产性猛交xxxx免费看久久| 成人国产精品久久久| 欧美成人激情视频免费观看| 国产成人精品综合久久久| 国产成人精品久久二区二区91| 国产91对白在线播放| 亚洲自拍av在线| 日韩电影视频免费| 91视频免费在线| 欧美精品成人91久久久久久久| 美女精品久久久| 欧美国产乱视频| 精品国产精品三级精品av网址| 欧美性受xxxx黑人猛交| 国产色视频一区| 国产精品综合网站| 91亚洲国产成人精品性色| 久久久国产精品x99av| 8x海外华人永久免费日韩内陆视频| xvideos成人免费中文版| 久久99国产综合精品女同| 日韩精品中文字| 姬川优奈aav一区二区| 亚洲91精品在线观看| 精品国产一区二区三区久久久狼| 国产精品爽爽ⅴa在线观看| 精品久久久久久久久久| 亚洲欧美国产精品专区久久| 日韩电影第一页| 日韩在线观看视频免费| 红桃av永久久久| 在线观看国产精品91| 国产精品视频在线观看| 97国产成人精品视频| 国产精品igao视频| 日韩中文字幕免费视频| 日韩中文字幕在线看| 尤物99国产成人精品视频| 欧美精品日韩三级| 国产午夜精品免费一区二区三区| 欧美视频在线观看 亚洲欧| www.亚洲一二| 亚洲欧美日韩中文视频| 国产精品白丝av嫩草影院| 精品一区二区三区四区在线| 亚洲精品自拍第一页| 色yeye香蕉凹凸一区二区av| 亚洲美女性视频| 久久久久国产视频| 国产精品视频资源| 久久亚洲国产精品成人av秋霞| 日本精品中文字幕| 日韩高清免费在线| 高清日韩电视剧大全免费播放在线观看| 国产亚洲人成a一在线v站| 久久99久久99精品中文字幕| 97国产在线观看| 亚洲综合色激情五月| 一区二区三区精品99久久| 91国内在线视频| 欧美精品制服第一页| 精品国模在线视频| 欧美极品少妇xxxxⅹ喷水| 日韩有码在线观看| 日韩欧美亚洲一二三区| 亚洲人在线视频| 亚洲第一网站男人都懂| 2024亚洲男人天堂| 色香阁99久久精品久久久| 日韩欧美极品在线观看| 欧美色图在线视频| 国产精品一区=区| 亚洲国产成人一区| 91精品视频在线免费观看| 91久久精品久久国产性色也91| 尤物精品国产第一福利三区| 亚洲字幕在线观看| 成人精品视频久久久久| 日韩美女在线播放| xvideos亚洲| 亚洲影院色在线观看免费| 欧美精品日韩www.p站| 92看片淫黄大片欧美看国产片| 色偷偷噜噜噜亚洲男人| 久久国产精品偷| 国产一区二区三区在线视频| 久久精品国产91精品亚洲| 亚洲欧美国产精品久久久久久久| 成人在线中文字幕| 亚洲va欧美va国产综合久久| 一区二区av在线| 亚洲视频精品在线| 不卡av电影院| 一区二区三区回区在观看免费视频| 亚洲久久久久久久久久久| 国产精品国内视频| 国自在线精品视频| 91精品久久久久久久久久久| 欧美一级大胆视频| 欧美精品在线免费| 国产精品视频最多的网站| 亚洲自拍偷拍福利| 日韩欧美亚洲综合| 伊人亚洲福利一区二区三区|