面試10家公司,識訓9個offer,2020年PHP 面試問題
ps:本篇內容包括精選面試題與知識篇,
PHP面試題關于PHP的垃圾回識訓制,PHP的垃圾回識訓制參考計數 (reference counting) GC 機制,PHP可以自動進行記憶體管理,清除不需要的物件,PHP面試題分享PHP關于垃圾回識訓制的面試題:
★我的php學習交流社群——856460874,群內管理已準備好 整理好的BAT等一線大廠進階知識體系備好(相關學習資料以及筆面試題)歡迎獲取一起晉升=點擊加
面試題篇
- 介紹一下PHP的垃圾回識訓制
PHP使用了參考計數(reference counting)GC機制,同時使用根緩沖區機制,當php發現有存在回圈參考的zval時,就會把其投入到根緩沖區,當根緩沖區達到組態檔中的指定數量后,就會進行垃圾回收,以此解決回圈參考導致的記憶體泄漏問題,
- 1. 如果參考計數減少到零,所在變數容器將被清除(free),不屬于垃圾;
- 2. 如果一個zval的參考計數減少后還大于0,那么它會進入垃圾周期,其次,在一個垃圾周期中,通過檢查參考計數是否減1,并且檢查哪些變數容器的參考次數是零,來發現哪部分是垃圾,
每個物件都內含一個參考計數器refcount,每個reference連接到物件,計數器加1,當reference離開生存空間或被設為 NULL,計數器減1,當某個物件的參考計數器為零時,PHP知道你將不再需要使用這個物件,釋放其所占的記憶體空間,
- 下列關于PHP垃圾回收的說法,錯誤的是?
A、開啟/關閉垃圾回識訓制可以通過修改php配置實作
B、可以在程式中使用gc_enable() 和 gc_disable()開啟和關閉,
C、PHP中的垃圾回識訓制,會大幅度提升系統性能,
D、開啟垃圾回識訓制后,針對記憶體泄露的情況,可以節省大量的記憶體空間,但是由于垃圾回收演算法運行耗費時間,開啟垃圾回收演算法會增加腳本的執行時間,
參考答案:C
答案決議:PHP中的垃圾回識訓制,僅僅在回圈回收演算法確實運行時會有時間消耗上的增加,但是在平常的(更小的)腳本中應根本就沒有性能影響,
- php垃圾回識訓制的說法錯誤的是?
A、在一個垃圾周期中,通過檢查參考計數是否減1,并且檢查哪些變數容器的參考次數是零,來發現哪部分是垃圾
B、可以通過呼叫gc_enable() 和 gc_disable()函式來打開和關閉垃圾回識訓制
C、通過清理未被使用的變數來節省記憶體的占用
D、php代碼執行完畢后會自動執行垃圾回收,所以不需要手動執行垃圾回收
參考答案:D
答案決議:php一段代碼有可能要長時間執行,但若此期間有未參考的變數的話,就會占用記憶體的空間,導致運行緩慢等問題
知識篇
一、概念
垃圾回收是一個多數編程語言中都帶有的記憶體管理機制,與非托管性語言相反:C, C++ 和 Objective C,用戶需要手動收集記憶體,帶有 GC 機制的語言:Java, javaScript 和 PHP 可以自動管理記憶體,
垃圾回識訓制(gc)顧名思義,就是廢物重利用的意思,是一種動態存盤分配的方案,它會自動釋放程式不再需要的已分配的記憶體塊,垃圾回識訓制可以讓程式員不必過分關心程式記憶體分配,從而將更多的精力投入到業務邏輯,
在現在的流行各種語言當中,垃圾回識訓制是新一代語言所共有的特征,如Python、PHP、C#、Ruby等都使用了垃圾回識訓制,
二、PHP垃圾回識訓制
1、在PHP5.3版本之前,使用的垃圾回識訓制是單純的“參考計數”,
什么叫做參考計數?
由于PHP是用C來寫的,C里面有一種東西叫做結構體,我們PHP的變數在C中就是用這種方式存盤的,
每個PHP的變數都存在于一個叫做zval的容器中,一個zval容器,除了包含變數名和值,還包括兩個位元組的額外資訊:
● 一個叫做'is_ref',是個布林值,用來表示這個變數是否屬于參考集合,通過這個位元組,我們php才能把普通變數和參考變數區分開來,
● 第二個額外位元組就是'refcount',用來表示指向這個容器的變數的個數,
即:
① 每個記憶體物件都分配一個計數器,當記憶體物件被變數參考時,計數器+1;
② 當變數參考撤掉后(執行unset()后),計數器-1;
③ 當計數器=0時,表明記憶體物件沒有被使用,該記憶體物件則進行銷毀,垃圾回收完成,
并且PHP在一個生命周期結束后就會釋放此行程/執行緒所占的內容,這種方式決定了PHP在前期不需要過多考慮記憶體的泄露問題,
但是當兩個或多個物件互相參考形成環狀后,記憶體物件的計數器則不會消減為0;這時候,這一組記憶體物件已經沒用了,但是不能回收,從而導致記憶體泄露的現象,
php5.3開始,使用了新的垃圾回識訓制,在參考計數基礎上,實作了一種復雜的演算法,來檢測記憶體物件中參考環的存在,以避免記憶體泄露,
- 2、隨著PHP的發展,PHP開發者的增加以及其所承載的業務范圍的擴大,在PHP5.3中引入了更加完善的垃圾回識訓制,新的垃圾回識訓制解決了無法處理回圈的參考記憶體泄漏問題,
如官方檔案所說:每個php變數存在一個叫"zval"的變數容器中,一個zval變數容器,除了包含變數的型別和值,還包括兩個位元組的額外資訊,第一個是"is_ref",是個bool值,用來標識這個變數是否是屬于參考集合(reference set),通過這個位元組,php引擎才能把普通變數和參考變數區分開來,由于php允許用戶通過使用&來使用自定義參考,zval變數容器中還有一個內部參考計數機制,來優化記憶體使用,
第二個額外位元組是"refcount",用以表示指向這個zval變數容器的變數(也稱符號即symbol)個數,所有的符號存在一個符號表中,其中每個符號都有作用域(scope),
官方檔案所說,可以使用Xdebug來檢查參考計數情況:
<?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版本開始,以上例程的參考將不再被計數,即$c=$b=$a之后a的參考計數也是1.具體分類如下:
在PHP 7中,zval可以被參考計數或不被參考,在zval結構中有一個標志確定了這一點,
① 對于null,bool,int和double的型別變數,refcount永遠不會計數;
② 對于物件、資源型別,refcount計數和php5的一致;
③ 對于字串,未被參考的變數被稱為“實際字串”,而那些被參考的字串被重復洗掉(即只有一個帶有特定內容的被插入的字串)并保證在請求的整個持續時間記憶體在,所以不需要為它們使用參考計數;如果使用了opcache,這些字串將存在于共享記憶體中,在這種情況下,您不能使用參考計數(因為我們的參考計數機制是非原子的);
④對于陣列,未參考的變數被稱為“不可變陣列”,其陣列本身計數與php5一致,但是陣列里面的每個鍵值對的計數,則按前面三條的規則(即如果是字串也不在計數);如果使用opcache,則代碼中的常量陣列文字將被轉換為不可變陣列,
再次,這些生活在共享記憶體,因此不能使用refcounting,
我們的demo例子如下:
<?php
echo '測驗字串參考計數';
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
unset( $b);
xdebug_debug_zval( 'a' );
$b = &$a;
xdebug_debug_zval( 'a' );
echo '測驗陣列參考計數';
$c = array('a','b');
xdebug_debug_zval( 'c' );
$d = $c;
xdebug_debug_zval( 'c' );
$c[2]='c';
xdebug_debug_zval( 'c' );
echo '測驗int型計數';
$e = 1;
xdebug_debug_zval( 'e' );
看到的輸出如下:

三、回收周期
默認的,PHP的垃圾回識訓制是打開的,然后有個php.ini設定允許你修改它:zend.enable_gc ,
當垃圾回識訓制打開時,演算法會判斷每當根快取區存滿時,就會執行回圈查找,根快取區有固定的大小,默認10,000,可以通過修改PHP原始碼檔案Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新編譯PHP,來修改這個值,當垃圾回識訓制關閉時,回圈查找演算法永不執行,然而,根將一直存在根緩沖區中,不管在配置中垃圾回識訓制是否激活,
除了修改配置zend.enable_gc ,也能通過分別呼叫gc_enable() 和 gc_disable()函式在運行php時來打開和關閉垃圾回識訓制,呼叫這些函式,與修改配置項來打開或關閉垃圾回識訓制的效果是一樣的,即使在可能根緩沖區還沒滿時,也能強制執行周期回收,你能呼叫gc_collect_cycles()函式達到這個目的,這個函式將回傳使用這個演算法回收的周期數,
允許打開和關閉垃圾回識訓制并且允許自主的初始化的原因,是由于你的應用程式的某部分可能是高時效性的,在這種情況下,你可能不想使用垃圾回識訓制,當然,對你的應用程式的某部分關閉垃圾回識訓制,是在冒著可能記憶體泄漏的風險,因為一些可能根也許存不進有限的根緩沖區,
因此,就在你呼叫gc_disable()函式釋放記憶體之前,先呼叫gc_collect_cycles()函式可能比較明智,因為這將清除已存放在根緩沖區中的所有可能根,然后在垃圾回識訓制被關閉時,可留下慷訓沖區以有更多空間存盤可能根,
四、性能影響
1、記憶體占用空間的節省
首先,實作垃圾回識訓制的整個原因是為了一旦先決條件滿足,通過清理回圈參考的變數來節省記憶體占用,在PHP執行中,一旦根緩沖區滿了或者呼叫gc_collect_cycles() 函式時,就會執行垃圾回收,
2、執行時間增加
垃圾回收影響性能的第二個領域是它釋放已泄漏的記憶體耗費的時間,
通常,PHP中的垃圾回識訓制,僅僅在回圈回收演算法確實運行時會有時間消耗上的增加,但是在平常的(更小的)腳本中應根本就沒有性能影響,
3、在平常腳本中有回圈回識訓制運行的情況下,記憶體的節省將允許更多這種腳本同時運行在你的服務器上,因為總共使用的記憶體沒達到上限,
這種好處在長時間運行腳本中尤其明顯,諸如長時間的測驗套件或者daemon腳本此類,同時,對通常比Web腳本運行時間長的腳本應用程式,新的垃圾回識訓制,應該會大大改變一直以來認為記憶體泄漏問題難以解決的看法,
最后,祝所有大家在面試中過關斬將,拿到心儀offer,
對此我整理了一些資料,包括但不限于:分布式架構、高可擴展、高性能、高并發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階干貨需要的可以免費分享給大家
如果想與一群3-8年資深開發者一起交流學習的話,需要,我的官方群-點擊此處,
騰訊T3-T4標準精品PHP架構師教程目錄大全,只要你看完保證薪資上升一個臺階(持續更新)?!
本文由博客群發一文多發等運營工具平臺 OpenWrite 發布
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/1933.html
標籤:PHP
上一篇:寶塔面板搭建個人網站
