PHP垃圾回收機制學(xué)習(xí)記錄

參考文章:垃圾回收

說在最前面:垃圾回收就是 處理無用的變量及其所關(guān)聯(lián)內(nèi)存的一種操作含友。

1. 基本思想

想說清楚PHP的垃圾回收機制吩蔑,需要從變量的實現(xiàn)說起(詳細說明請查看)钮热。變量的值存儲到以下所示zval結(jié)構(gòu)體中:

typedef struct _zval_struct zval;
...
struct _zval_struct {
    zvalue_value value;     /* 變量值 */
    zend_uchar type;    /* 變量類型 */
    zend_uint refcount__gc;     /* 引用計數(shù),默認值為1 */
    zend_uchar is_ref__gc;    /* 是否被引用烛芬,默認值為0 */
};

當一個變量$a被賦值時就會生成一個zval變量容器隧期,此時refcount__gc=1,當$a再賦值給其他的變量$b時赘娄,此時不再產(chǎn)生新的zval變量容器仆潮,而是將$b指向$a的zval變量容器,如下所示:

<?php
$a = "new string";
xdebug_debug_zval( 'a' );
//輸出:a: (refcount=1, is_ref=0)='new string'
$b = $a;
xdebug_debug_zval( 'a' );
//輸出:a: (refcount=2, is_ref=0)='new string'

當變量離開它的作用域(比如:函數(shù)執(zhí)行結(jié)束)遣臼,或者對變量調(diào)用了函數(shù) unset()時性置,”refcount“就會減1,當”refcount“減為0時揍堰,則變量容器被銷毀鹏浅,內(nèi)存被回收。

2. 新老垃圾回收方式對比

PHP5.2中的垃圾回收算法——Reference Counting :

PHP5.2中使用的內(nèi)存回收算法是大名鼎鼎的Reference Counting屏歹,中文翻譯叫做“引用計數(shù)”隐砸,其思想非常直觀和簡潔:為每個內(nèi)存對象分配一個計數(shù)器,當一個內(nèi)存對象建立時計數(shù)器初始化為1(因此此時總是有一個變量引用此對象)蝙眶,以后每有一個新變量引用此內(nèi)存對象季希,則計數(shù)器加1,而每當減少一個引用此內(nèi)存對象的變量則計數(shù)器減1,當垃圾回收機制運作的時候式塌,將所有計數(shù)器為0的內(nèi)存對象銷毀并回收其占用的內(nèi)存武通。

缺點: 這種方式雖然簡單直觀,實現(xiàn)方便珊搀,但卻存在一個致命的缺陷冶忱,就是容易造成內(nèi)存泄露,就是當兩個或多個對象互相引用形成環(huán)狀后境析,內(nèi)存對象的計數(shù)器則不會消減為0囚枪;這時候,這一組內(nèi)存對象已經(jīng)沒用了劳淆,但是不能回收链沼,從而導(dǎo)致內(nèi)存泄露;沛鸵。

為解決環(huán)形引用導(dǎo)致的垃圾括勺,產(chǎn)生了新的垃圾回收算法,遵守以下幾個基本準則:
1.如果一個zval的refcount減少到0曲掰, 那么zval可以被釋放掉疾捍,不屬于垃圾
2.如果一個zval的refcount減少之后大于0,那么此zval還不能被釋放栏妖,此zval可能成為一個垃圾

PHP5.3中的新垃圾回收算法——Concurrent Cycle Collection in Reference Counted Systems :

PHP會分配一個固定大小的“根緩沖區(qū)”乱豆,這個緩沖區(qū)可存放10000個的zval容器,當根緩沖區(qū)滿或內(nèi)存不足時吊趾,PHP就會執(zhí)行垃圾回收宛裕。為了避免每次變量的refcount減少的時候都調(diào)用算法進行垃圾判斷,算法會先把準則3情況下的zval節(jié)點放入節(jié)點緩沖區(qū)论泛,并標記成紫色揩尸,確保每個節(jié)點在緩沖區(qū)中只出現(xiàn)一次。
算法會分以下三步進行:MarkRoots()屁奏、ScanRoots()岩榆、CollectRoots()

  1. 從buffer鏈表的roots開始遍歷,把當前value標為灰色了袁,然后對當前value的成員進行深度優(yōu)先遍歷朗恳,把成員value的refcount減1,并且也標為灰色载绿;
  2. 重復(fù)遍歷buffer鏈表粥诫,檢查當前value引用是否為0,為0則表示確實是垃圾崭庸,把它標為白色怀浆,如果不為0則排除了引用全部來自自身成員的可能谊囚,表示還有外部的引用,并不是垃圾执赡,這時候因為步驟(1)對成員進行了refcount減1操作镰踏,需要再還原回去,對所有成員進行深度遍歷沙合,把成員refcount加1奠伪,同時標為黑色;
  3. 再次遍歷buffer鏈表首懈,將非白色的節(jié)點從roots鏈表中刪除绊率,最終roots鏈表中全部為真正的垃圾,最后將這些垃圾清除究履。

PHP5.3的垃圾回收算法特性總結(jié):
1滤否、并不是每次refcount減少時都進入回收周期,只有根緩沖區(qū)滿額后在開始垃圾回收最仑。
2藐俺、可以解決循環(huán)引用問題。
3泥彤、可以總將內(nèi)存泄露保持在一個閾值以下欲芹。

注意:同步周期回收算法 原文中的3.1節(jié) Pseudocode and Explanatio,對算法有詳細描述

image.png

3. 與垃圾回收算法相關(guān)的PHP配置

可以通過修改php.ini中的zend.enable_gc來打開或關(guān)閉PHP的垃圾回收機制
或通過調(diào)用gc_enable()打開全景、gc_disable()關(guān)閉
或手工調(diào)用gc_collect_cycles()函數(shù)強制執(zhí)行內(nèi)存回收耀石。

4. 垃圾回收機制對性能的影響

PHP中的垃圾回收機制,僅僅在循環(huán)回收算法運行時會有時間消耗上的增加爸黄。但是在平常的(更小的)腳本中根本就沒有性能影響。
但是揭鳞,在平常腳本中有循環(huán)回收機制運行的情況下炕贵,內(nèi)存的節(jié)省將允許更多這種腳本同時運行在你的服務(wù)器上。因為總共使用的內(nèi)存沒達到上限野崇,這種好處在長時間運行腳本中尤其明顯称开。

5. 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別

內(nèi)存溢出 out of memory,是指程序在申請內(nèi)存時乓梨,沒有足夠的內(nèi)存空間供其使用鳖轰,出現(xiàn)out of memory;比如申請了一個integer,但給它存了long才能存下的數(shù)扶镀,那就是內(nèi)存溢出蕴侣。
內(nèi)存泄露 memory leak,是指程序在申請內(nèi)存后臭觉,無法釋放已申請的內(nèi)存空間昆雀,一次內(nèi)存泄露危害可以忽略辱志,但內(nèi)存泄露堆積后果很嚴重,無論多少內(nèi)存,遲早會被占光狞膘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揩懒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子挽封,更是在濱河造成了極大的恐慌已球,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辅愿,死亡現(xiàn)場離奇詭異和悦,居然都是意外死亡,警方通過查閱死者的電腦和手機渠缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門鸽素,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亦鳞,你說我怎么就攤上這事馍忽。” “怎么了燕差?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵遭笋,是天一觀的道長。 經(jīng)常有香客問我徒探,道長瓦呼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任测暗,我火速辦了婚禮央串,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碗啄。我一直安慰自己质和,他們只是感情好,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布稚字。 她就那樣靜靜地躺著饲宿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胆描。 梳的紋絲不亂的頭發(fā)上瘫想,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音昌讲,去河邊找鬼国夜。 笑死,一個胖子當著我的面吹牛剧蚣,可吹牛的內(nèi)容都是我干的支竹。 我是一名探鬼主播旋廷,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼礼搁!你這毒婦竟也來了饶碘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤馒吴,失蹤者是張志新(化名)和其女友劉穎扎运,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饮戳,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡豪治,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扯罐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片负拟。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖歹河,靈堂內(nèi)的尸體忽然破棺而出掩浙,到底是詐尸還是另有隱情,我是刑警寧澤秸歧,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布厨姚,位于F島的核電站,受9級特大地震影響键菱,放射性物質(zhì)發(fā)生泄漏谬墙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一经备、第九天 我趴在偏房一處隱蔽的房頂上張望拭抬。 院中可真熱鬧,春花似錦弄喘、人聲如沸玖喘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贬派,卻和暖如春急但,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搞乏。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工波桩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人请敦。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓镐躲,卻偏偏與公主長得像储玫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子萤皂,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容