PHP的垃圾回收機制-PHP高級面試題+詳解

面試10家公司挣饥,收獲9個offer,2020年PHP 面試問題

ps:本篇內(nèi)容包括精選面試題與知識篇沛膳。

PHP面試題關于PHP的垃圾回收機制扔枫,PHP的垃圾回收機制引用計數(shù) (reference counting) GC 機制,PHP可以自動進行內(nèi)存管理锹安,清除不需要的對象短荐,PHP面試題分享PHP關于垃圾回收機制的面試題:

★我的php學習交流社群——856460874。群內(nèi)管理已準備好 整理好的BAT等一線大廠進階知識體系備好(相關學習資料以及筆面試題)歡迎獲取一起晉升=點擊加

面試題篇

  • 介紹一下PHP的垃圾回收機制

PHP使用了引用計數(shù)(reference counting)GC機制叹哭,同時使用根緩沖區(qū)機制忍宋,當php發(fā)現(xiàn)有存在循環(huán)引用的zval時,就會把其投入到根緩沖區(qū)风罩,當根緩沖區(qū)達到配置文件中的指定數(shù)量后糠排,就會進行垃圾回收,以此解決循環(huán)引用導致的內(nèi)存泄漏問題超升。

  • 1. 如果引用計數(shù)減少到零入宦,所在變量容器將被清除(free),不屬于垃圾室琢;
  • 2. 如果一個zval的引用計數(shù)減少后還大于0乾闰,那么它會進入垃圾周期。其次盈滴,在一個垃圾周期中涯肩,通過檢查引用計數(shù)是否減1,并且檢查哪些變量容器的引用次數(shù)是零巢钓,來發(fā)現(xiàn)哪部分是垃圾病苗。

每個對象都內(nèi)含一個引用計數(shù)器refcount,每個reference連接到對象竿报,計數(shù)器加1铅乡。當reference離開生存空間或被設為 NULL,計數(shù)器減1烈菌。當某個對象的引用計數(shù)器為零時阵幸,PHP知道你將不再需要使用這個對象花履,釋放其所占的內(nèi)存空間。

  • 下列關于PHP垃圾回收的說法挚赊,錯誤的是诡壁?

A、開啟/關閉垃圾回收機制可以通過修改php配置實現(xiàn)

B荠割、可以在程序中使用gc_enable() 和 gc_disable()開啟和關閉妹卿。

C、PHP中的垃圾回收機制蔑鹦,會大幅度提升系統(tǒng)性能夺克。

D、開啟垃圾回收機制后嚎朽,針對內(nèi)存泄露的情況铺纽,可以節(jié)省大量的內(nèi)存空間,但是由于垃圾回收算法運行耗費時間哟忍,開啟垃圾回收算法會增加腳本的執(zhí)行時間狡门。

參考答案:C
答案解析:PHP中的垃圾回收機制,僅僅在循環(huán)回收算法確實運行時會有時間消耗上的增加锅很。但是在平常的(更小的)腳本中應根本就沒有性能影響其馏。

  • php垃圾回收機制的說法錯誤的是?

A爆安、在一個垃圾周期中叛复,通過檢查引用計數(shù)是否減1,并且檢查哪些變量容器的引用次數(shù)是零鹏控,來發(fā)現(xiàn)哪部分是垃圾

B致扯、可以通過調(diào)用gc_enable() 和 gc_disable()函數(shù)來打開和關閉垃圾回收機制

C、通過清理未被使用的變量來節(jié)省內(nèi)存的占用

D当辐、php代碼執(zhí)行完畢后會自動執(zhí)行垃圾回收抖僵,所以不需要手動執(zhí)行垃圾回收

參考答案:D
答案解析:php一段代碼有可能要長時間執(zhí)行,但若此期間有未引用的變量的話缘揪,就會占用內(nèi)存的空間耍群,導致運行緩慢等問題


知識篇

一、概念

垃圾回收是一個多數(shù)編程語言中都帶有的內(nèi)存管理機制找筝。與非托管性語言相反:C, C++ 和 Objective C蹈垢,用戶需要手動收集內(nèi)存,帶有 GC 機制的語言:Java, javaScript 和 PHP 可以自動管理內(nèi)存袖裕。

垃圾回收機制(gc)顧名思義曹抬,就是廢物重利用的意思,是一種動態(tài)存儲分配的方案急鳄。它會自動釋放程序不再需要的已分配的內(nèi)存塊谤民。垃圾回收機制可以讓程序員不必過分關心程序內(nèi)存分配堰酿,從而將更多的精力投入到業(yè)務邏輯。

在現(xiàn)在的流行各種語言當中张足,垃圾回收機制是新一代語言所共有的特征触创,如Python、PHP为牍、C#哼绑、Ruby等都使用了垃圾回收機制。

二碉咆、PHP垃圾回收機制

1抖韩、在PHP5.3版本之前,使用的垃圾回收機制是單純的“引用計數(shù)”。

什么叫做引用計數(shù)疫铜?
由于PHP是用C來寫的帽蝶,C里面有一種東西叫做結(jié)構(gòu)體,我們PHP的變量在C中就是用這種方式存儲的块攒。
每個PHP的變量都存在于一個叫做zval的容器中,一個zval容器佃乘,除了包含變量名和值囱井,還包括兩個字節(jié)的額外信息:
● 一個叫做'is_ref',是個布爾值趣避,用來表示這個變量是否屬于引用集合,通過這個字節(jié)庞呕,我們php才能把普通變量和引用變量區(qū)分開來。
● 第二個額外字節(jié)就是'refcount'程帕,用來表示指向這個容器的變量的個數(shù)住练。

即:

① 每個內(nèi)存對象都分配一個計數(shù)器,當內(nèi)存對象被變量引用時愁拭,計數(shù)器+1讲逛;

② 當變量引用撤掉后(執(zhí)行unset()后),計數(shù)器-1岭埠;

③ 當計數(shù)器=0時盏混,表明內(nèi)存對象沒有被使用,該內(nèi)存對象則進行銷毀惜论,垃圾回收完成许赃。

并且PHP在一個生命周期結(jié)束后就會釋放此進程/線程所占的內(nèi)容,這種方式?jīng)Q定了PHP在前期不需要過多考慮內(nèi)存的泄露問題馆类。

但是當兩個或多個對象互相引用形成環(huán)狀后混聊,內(nèi)存對象的計數(shù)器則不會消減為0;這時候乾巧,這一組內(nèi)存對象已經(jīng)沒用了句喜,但是不能回收预愤,從而導致內(nèi)存泄露的現(xiàn)象。

php5.3開始藤滥,使用了新的垃圾回收機制鳖粟,在引用計數(shù)基礎上,實現(xiàn)了一種復雜的算法拙绊,來檢測內(nèi)存對象中引用環(huán)的存在向图,以避免內(nèi)存泄露。

  • 2标沪、隨著PHP的發(fā)展榄攀,PHP開發(fā)者的增加以及其所承載的業(yè)務范圍的擴大,在PHP5.3中引入了更加完善的垃圾回收機制金句,新的垃圾回收機制解決了無法處理循環(huán)的引用內(nèi)存泄漏問題檩赢。

如官方文檔所說:每個php變量存在一個叫"zval"的變量容器中。一個zval變量容器违寞,除了包含變量的類型和值贞瞒,還包括兩個字節(jié)的額外信息。第一個是"is_ref"趁曼,是個bool值军浆,用來標識這個變量是否是屬于引用集合(reference set)。通過這個字節(jié)挡闰,php引擎才能把普通變量和引用變量區(qū)分開來乒融,由于php允許用戶通過使用&來使用自定義引用,zval變量容器中還有一個內(nèi)部引用計數(shù)機制摄悯,來優(yōu)化內(nèi)存使用赞季。

第二個額外字節(jié)是"refcount",用以表示指向這個zval變量容器的變量(也稱符號即symbol)個數(shù)奢驯。所有的符號存在一個符號表中申钩,其中每個符號都有作用域(scope)。

官方文檔所說叨橱,可以使用Xdebug來檢查引用計數(shù)情況:

<?php
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
unset( $b, $c );
xdebug_debug_zval( 'a' );
?>

以上例程會輸出:

a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'

注意:從PHP7的NTS版本開始典蜕,以上例程的引用將不再被計數(shù),即c=b=$a之后a的引用計數(shù)也是1.具體分類如下:

在PHP 7中罗洗,zval可以被引用計數(shù)或不被引用愉舔。在zval結(jié)構(gòu)中有一個標志確定了這一點。

① 對于null伙菜,bool轩缤,int和double的類型變量,refcount永遠不會計數(shù);

② 對于對象火的、資源類型壶愤,refcount計數(shù)和php5的一致;

③ 對于字符串馏鹤,未被引用的變量被稱為“實際字符串”征椒。而那些被引用的字符串被重復刪除(即只有一個帶有特定內(nèi)容的被插入的字符串)并保證在請求的整個持續(xù)時間內(nèi)存在,所以不需要為它們使用引用計數(shù)湃累;如果使用了opcache勃救,這些字符串將存在于共享內(nèi)存中,在這種情況下治力,您不能使用引用計數(shù)(因為我們的引用計數(shù)機制是非原子的)泳梆;

④對于數(shù)組屈溉,未引用的變量被稱為“不可變數(shù)組”奠支。其數(shù)組本身計數(shù)與php5一致拳缠,但是數(shù)組里面的每個鍵值對的計數(shù),則按前面三條的規(guī)則(即如果是字符串也不在計數(shù))马澈;如果使用opcache瓢省,則代碼中的常量數(shù)組文字將被轉(zhuǎn)換為不可變數(shù)組。

再次痊班,這些生活在共享內(nèi)存净捅,因此不能使用refcounting。

我們的demo例子如下:

<?php
echo '測試字符串引用計數(shù)';
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
unset( $b);
xdebug_debug_zval( 'a' );
$b = &$a;
xdebug_debug_zval( 'a' );
echo '測試數(shù)組引用計數(shù)';
$c = array('a','b');
xdebug_debug_zval( 'c' );
$d = $c;
xdebug_debug_zval( 'c' );
$c[2]='c';
xdebug_debug_zval( 'c' );
echo '測試int型計數(shù)';
$e = 1;
xdebug_debug_zval( 'e' );

看到的輸出如下:

三辩块、回收周期

默認的,PHP的垃圾回收機制是打開的荆永,然后有個php.ini設置允許你修改它:zend.enable_gc 废亭。

當垃圾回收機制打開時,算法會判斷每當根緩存區(qū)存滿時具钥,就會執(zhí)行循環(huán)查找豆村。根緩存區(qū)有固定的大小,默認10,000骂删,可以通過修改PHP源碼文件Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES掌动,然后重新編譯PHP,來修改這個值宁玫。當垃圾回收機制關閉時粗恢,循環(huán)查找算法永不執(zhí)行,然而欧瘪,根將一直存在根緩沖區(qū)中眷射,不管在配置中垃圾回收機制是否激活。

除了修改配置zend.enable_gc ,也能通過分別調(diào)用gc_enable() 和 gc_disable()函數(shù)在運行php時來打開和關閉垃圾回收機制妖碉。調(diào)用這些函數(shù)涌庭,與修改配置項來打開或關閉垃圾回收機制的效果是一樣的。即使在可能根緩沖區(qū)還沒滿時欧宜,也能強制執(zhí)行周期回收坐榆。你能調(diào)用gc_collect_cycles()函數(shù)達到這個目的。這個函數(shù)將返回使用這個算法回收的周期數(shù)冗茸。

允許打開和關閉垃圾回收機制并且允許自主的初始化的原因席镀,是由于你的應用程序的某部分可能是高時效性的。在這種情況下蚀狰,你可能不想使用垃圾回收機制愉昆。當然,對你的應用程序的某部分關閉垃圾回收機制麻蹋,是在冒著可能內(nèi)存泄漏的風險跛溉,因為一些可能根也許存不進有限的根緩沖區(qū)。

因此扮授,就在你調(diào)用gc_disable()函數(shù)釋放內(nèi)存之前芳室,先調(diào)用gc_collect_cycles()函數(shù)可能比較明智。因為這將清除已存放在根緩沖區(qū)中的所有可能根刹勃,然后在垃圾回收機制被關閉時堪侯,可留下空緩沖區(qū)以有更多空間存儲可能根。

四荔仁、性能影響

1伍宦、內(nèi)存占用空間的節(jié)省

首先,實現(xiàn)垃圾回收機制的整個原因是為了一旦先決條件滿足乏梁,通過清理循環(huán)引用的變量來節(jié)省內(nèi)存占用次洼。在PHP執(zhí)行中,一旦根緩沖區(qū)滿了或者調(diào)用gc_collect_cycles() 函數(shù)時遇骑,就會執(zhí)行垃圾回收卖毁。

2、執(zhí)行時間增加

垃圾回收影響性能的第二個領域是它釋放已泄漏的內(nèi)存耗費的時間落萎。

通常亥啦,PHP中的垃圾回收機制,僅僅在循環(huán)回收算法確實運行時會有時間消耗上的增加练链。但是在平常的(更小的)腳本中應根本就沒有性能影響翔脱。

3、在平常腳本中有循環(huán)回收機制運行的情況下媒鼓,內(nèi)存的節(jié)省將允許更多這種腳本同時運行在你的服務器上碍侦。因為總共使用的內(nèi)存沒達到上限粱坤。

這種好處在長時間運行腳本中尤其明顯,諸如長時間的測試套件或者daemon腳本此類瓷产。同時站玄,對通常比Web腳本運行時間長的腳本應用程序,新的垃圾回收機制濒旦,應該會大大改變一直以來認為內(nèi)存泄漏問題難以解決的看法株旷。

最后,祝所有大家在面試中過關斬將尔邓,拿到心儀offer晾剖。

對此我整理了一些資料,包括但不限于:分布式架構(gòu)梯嗽、高可擴展齿尽、高性能、高并發(fā)灯节、服務器性能調(diào)優(yōu)循头、TP6,laravel炎疆,YII2卡骂,Redis,Swoole形入、Swoft全跨、Kafka、Mysql優(yōu)化亿遂、shell腳本浓若、Docker、微服務蛇数、Nginx等多個知識點高級進階干貨需要的可以免費分享給大家

如果想與一群3-8年資深開發(fā)者一起交流學習的話七嫌,需要,我的官方群-點擊此處苞慢。

騰訊T3-T4標準精品PHP架構(gòu)師教程目錄大全,只要你看完保證薪資上升一個臺階(持續(xù)更新)?!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末英妓,一起剝皮案震驚了整個濱河市挽放,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔓纠,老刑警劉巖辑畦,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腿倚,居然都是意外死亡纯出,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暂筝,“玉大人箩言,你說我怎么就攤上這事』澜螅” “怎么了陨收?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸵赖。 經(jīng)常有香客問我务漩,道長,這世上最難降的妖魔是什么它褪? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任饵骨,我火速辦了婚禮,結(jié)果婚禮上茫打,老公的妹妹穿的比我還像新娘居触。我一直安慰自己,他們只是感情好包吝,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布饼煞。 她就那樣靜靜地躺著,像睡著了一般诗越。 火紅的嫁衣襯著肌膚如雪砖瞧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天嚷狞,我揣著相機與錄音块促,去河邊找鬼。 笑死床未,一個胖子當著我的面吹牛竭翠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薇搁,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼斋扰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了啃洋?” 一聲冷哼從身側(cè)響起传货,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宏娄,沒想到半個月后问裕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡孵坚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年粮宛,在試婚紗的時候發(fā)現(xiàn)自己被綠了窥淆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡巍杈,死狀恐怖忧饭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秉氧,我是刑警寧澤眷昆,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站汁咏,受9級特大地震影響亚斋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攘滩,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一帅刊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧漂问,春花似錦赖瞒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至磷仰,卻和暖如春袍嬉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灶平。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工伺通, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逢享。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓罐监,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瞒爬。 傳聞我的和親對象是個殘疾皇子弓柱,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351