面試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ù),即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ā)者一起交流學習的話七嫌,需要,我的官方群-點擊此處苞慢。