八年phper的高级工程师面试之路八年phper的高级工程师面试之路
這是一篇反面教材,希望也能引起部分程序員的警惕。
最近半個月時間,經(jīng)過幾次面試,差不多已經(jīng)對自己有了定位————距離騰訊T3崗位還是有一點距離。
因為在一家小公司呆的習(xí)慣了(6年),公司沒有人在技術(shù)層面超過我,作為技術(shù)核心,感覺自己很牛,活在一個小圈子里面,幾乎不會主動去了解新技術(shù),甚至對php以及js本身都不能算精通。
所以變故出現(xiàn)的時候,我才發(fā)現(xiàn)自己的技術(shù)脫節(jié)有多厲害,雖然之前的面試并沒有做專門的準(zhǔn)備,但是與6年前找工作的情形相比,差距非常的大。
下面是我整理的一部分遇到的面試題,我盡量用我所知道的知識來進行陳述,肯定會有很多誤解以及遺漏,希望大家能夠指正。
公司1:
1、mysql_real_escape_string mysql_escape_string有什么本質(zhì)的區(qū)別,有什么用處,為什么被棄用?
答:mysql_real_escape_string需要預(yù)先連接數(shù)據(jù)庫,并可在第二個參數(shù)傳入數(shù)據(jù)庫連接(不填則使用上一個連接)
兩者都是對數(shù)據(jù)庫插入數(shù)據(jù)進行轉(zhuǎn)義,但是mysql_real_escape_string轉(zhuǎn)義時,會考慮數(shù)據(jù)庫連接的字符集。
它們的用處都是用來能讓數(shù)據(jù)正常插入到數(shù)據(jù)庫中,并防止sql注入,但是并不能做到100%防止sql注入。
再問:為什么不能100%防止?
答;因為客戶端編碼以及服務(wù)器端編碼不同,可能產(chǎn)生注入問題,但是其實這種場景不多見。
繼續(xù)答:被棄用的原因是官方不再建議使用mysql_xx的數(shù)據(jù)庫操作方式,建議使用pdo和mysqli,因為不管從性能跟安全來看,mysqli都比mysql要好。
衍生出來的問題是mysqli的連接復(fù)用(持久化)問題,這一塊我并沒有答好。
2、什么是內(nèi)存泄漏,js內(nèi)存泄漏是怎么產(chǎn)生的?
答:內(nèi)存泄漏是因為一塊被分配內(nèi)存既不能被使用,也不能被回收,直到瀏覽器進程結(jié)束。
產(chǎn)生泄漏的原因是閉包維持函數(shù)內(nèi)局部變量,不能被釋放,尤其是使用閉包并存在外部引用還setInterval的時候危害很大。
備注:我覺得這塊回答并不好,因為肯定不是閉包的原因。
我查了一下資料,從比較淺的方位來再回答一下這個問題:
產(chǎn)生泄漏的原因有好幾種:
(1) 頁面元素被刪除,但是綁定在該元素上的事件未被刪除;
(2) 閉包維持函數(shù)內(nèi)局部變量(外部不可控),使其得不到釋放;
(3) 意外的全局變量;
(4) 引用被刪除,但是引用內(nèi)的引用,還存在內(nèi)存中。
從上述原因上看,內(nèi)存泄漏產(chǎn)生的根本原因是引用無法正確回收,值類型并不能引發(fā)內(nèi)存泄漏。
對于每個引用,都有自己的引用計數(shù),當(dāng)引用計數(shù)歸零或被標(biāo)記清除時,js垃圾回收器會認為該引用可以回收了。
3、什么是閉包,跟原型鏈、作用域鏈有什么關(guān)聯(lián)
答:閉包是指存在于一個作用域鏈分支的函數(shù)域內(nèi)的函數(shù),該函數(shù)可以向上逐級訪問作用域鏈上的變量,直到找到為止。當(dāng)閉包存在外部引用時,js會維持閉包自身以及所在函數(shù)作用域鏈的內(nèi)存狀態(tài)。
備注:這個是我自己瞎說的。
繼續(xù)答:跟原型鏈沒有什么關(guān)聯(lián),函數(shù)的原型(prototype)主要用于實現(xiàn)繼承,原型鏈可用于追溯繼承關(guān)系,與作用域鏈類似,都是向上逐級訪問屬性,直到被找到,原型鏈的頂層是null,可以理解為所有的object都繼承至null,所以null的類型是object。
繼續(xù)答:作用域鏈可以看作是一個樹形結(jié)構(gòu),由根節(jié)點window向下擴散,下層節(jié)點可以訪問上層節(jié)點,但是上層節(jié)點無法訪問下層節(jié)點,產(chǎn)生閉包的函數(shù)作用域?qū)儆诠?jié)點中的一個,向下擴散后閉包函數(shù)產(chǎn)生葉子節(jié)點,葉子節(jié)點之間可以互相訪問,當(dāng)訪問的變量在葉子節(jié)點中無法找到時,向上層節(jié)點查找,直到被找到為止,這個概念有點類似原型鏈上的屬性查找。
4、一臺電腦配置無限好,可以同時打開多少個網(wǎng)頁
答:65535-1000 = 64535(端口數(shù))
5、ip地址能被偽造嗎?
答:http頭部可以被篡改,但是只能修改X_FORWARDED_FOR,真實ip地址(REMOTE_ADDR)很難修改(除非是路由器去修改),因為真實ip是底層會話ip地址,而且因為TCP 3次握手的存在,連接無法建立,偽造的意義不大,至于UDP的話,一般是內(nèi)網(wǎng)才使用UDP通信。
6、有100萬個獎品,每個人可以中獎3次,先到先得,怎么控制并發(fā),不能發(fā)超,并保證完全的先到先得模式
答:百萬獎品在打亂后預(yù)先insert到數(shù)據(jù)庫,所有中獎操作,均只能update,不能insert。進來抽獎的用戶使用memcahe原子加鎖,實現(xiàn)抽獎次數(shù)自增,當(dāng)抽獎次數(shù)到達3時,返回不中獎。
再問:預(yù)先插入需要很多資源,如果獎品數(shù)量上了1億怎么辦?
答:使用redis隊列存儲請求,跑守護進程異步發(fā)獎,產(chǎn)生的問題是用戶無法實時看到中獎情況。
再問:這樣肯定不行。
再答:使用全局內(nèi)存加鎖確保抽獎過程是單進程在跑,但是會面臨大并發(fā)阻塞問題。
再問:內(nèi)存比較寶貴,在不用內(nèi)存加鎖的情況下怎么辦,并且如果碰到1億獎池的情況,預(yù)先插入數(shù)據(jù)庫肯定不好,怎么辦?
答:設(shè)置獎品概率,分三張表,都使用innodb引擎,一張存中獎記錄(預(yù)先插入一行),一張存獎品發(fā)放概況,一張存用戶抽獎情況(uin唯一索引),大并發(fā)情況下,利用mysql的排他鎖進行并發(fā)控制。流程如下:
begin
查詢用戶抽獎次數(shù),加排他鎖
對用戶抽獎次數(shù)的更新/插入
鎖行查詢發(fā)放情況
獲得抽獎結(jié)果(某些獎品發(fā)完之后,動態(tài)變更概率)
更新發(fā)放表
插入中獎記錄
commit
再問:遇到臟讀怎么辦?
答:這方面不是很了解
再問:innodb的master線程在什么情況下fork其他子線程?
答:不知道
7、數(shù)據(jù)鏈路層的數(shù)據(jù)是怎么校驗的,有哪些校驗方式?
答:crc32,別的校驗可能是取模校驗奇偶數(shù)吧。
備注:答個crc校驗就行了。
8、b+樹的查詢時間復(fù)雜度是多少,哈希表是多少,為什么數(shù)據(jù)庫索引用b+樹存儲,而不是哈希表,數(shù)據(jù)庫索引存儲還有其他數(shù)據(jù)結(jié)構(gòu)嗎?
答:O(log(n)),O(1)
因為哈希表是散列的,在遇到`key`>'12'這種查找條件時,不起作用,并且空間復(fù)雜度較高。
備注:b+數(shù)根據(jù)層數(shù)決定時間復(fù)雜度,數(shù)據(jù)量多的情況下一般4-5層,然后用二分法查找頁中的數(shù)據(jù),時間復(fù)雜度遠小于log(n)。
9、apache是怎么跟php通訊的,sapi是什么
答:使用sapi通訊,sapi是php封裝的對外數(shù)據(jù)傳遞接口,通常有cgi/fastcgi/cli/apache2handler四種運行模式。
10、php的垃圾回收機制?
答:垃圾回收是指當(dāng)php運行狀態(tài)結(jié)束時,比如遇到了exit/die/致命錯誤/腳本運行結(jié)束時,php需要回收運行過程中創(chuàng)建的變量、資源的內(nèi)存。
ZEND引擎維護了一個棧zval,每個創(chuàng)建的變量和資源都會壓入這個棧中,每個壓入的數(shù)組結(jié)構(gòu)都類似:[refcount => int, is_ref => 0|1, value => union, type => string],變量被unset時,ref_count如果變成0,則被回收。
當(dāng)遇到變量循環(huán)引用自身時,使用同步回收算法回收。
備注:PHP7已經(jīng)重寫了zal的結(jié)構(gòu)體。
11、jquery的sizzle引擎工作原理
答:除了直到是DOM元素查找引擎之外,一無所知。
12、seajs的工作原理,如何解決重復(fù)加載庫的問題,如何進行資源的同步加載
答:建立映射關(guān)系并緩存起來;資源并不能真正同步加載,只是返回一個回調(diào)。
13、memcache跟redis的區(qū)別
答:可存儲數(shù)據(jù)結(jié)構(gòu)不同;redis支持持久化存儲。
14、md5逆向原理
答:先用字典查找,再嘗試暴力破解。
再問:沒有更好的方法了嗎?
答:沒有了。
備注:嗯,事實上也確實沒有特別好的辦法,只能使用TB級的海量特征庫用數(shù)據(jù)庫存起來,然再分片查找。
15、父類方法是protected,子類重構(gòu)為private,會發(fā)生什么?
答:會發(fā)生fatal錯誤,因為繼承的方法或?qū)傩灾荒芫S持或放大權(quán)限,不能縮小,比如protected重載為public是可行的。
16、一個網(wǎng)頁從輸入地址回車,到完整展示網(wǎng)頁內(nèi)容這段時間里,做了哪些工作,越詳細越好。
答:
0、瀏覽器本地緩存匹配;
1、本地hosts映射對比;
2、本地dns緩存解析;
3、遠程dns解析獲得服務(wù)器ip地址;
4、瀏覽器發(fā)送tcp連接請求包(syn);
5、請求包經(jīng)過傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層封裝通過網(wǎng)卡到達路由器;
6、路由器轉(zhuǎn)發(fā)數(shù)據(jù)包到所屬運營商服務(wù)器;
7、運營商服務(wù)器通過尋址最短路徑通過中繼節(jié)點到達指定ip地址;
8、服務(wù)器端可能存在反向代理或者負載均衡,都是直接轉(zhuǎn)發(fā)請求至上游服務(wù)器,當(dāng)然也可以制定安全防御規(guī)則直接丟棄請求包;
9、上游服務(wù)器收到連接請求,在自身可用的情況下,返回(syn+ack);
10、瀏覽器校驗ack,再次發(fā)送(syn+ack);
11、服務(wù)器校驗ack切換連接狀態(tài)至established,然后根據(jù)請求傳輸數(shù)據(jù)包;
12、當(dāng)transform-encoding為chunked時,瀏覽器開始渲染頁面;
13、四次揮手,連接關(guān)閉;
14、渲染數(shù)據(jù)完成。
備注:還有很多東西不懂,一些東西完全是自己瞎蒙的,因為時間原因,以后有時間詳細畫一下。
17、keep-alive的概念
答:長連接機制,表示keep-alive-timeout時間內(nèi),如果連接沒有closed,再次傳輸數(shù)據(jù)不再需要三次握手了。
備注:這里也有很多疑問,需要好好捋一捋。
18、linux文件壓縮操作命令,shell腳本等
備注:因為平時開發(fā)都是在windows環(huán)境,對linux了解不足,這一塊幾乎是0分。
公司2:
這個是被鄙視最慘的一家了,首先會有筆試,相對來說并不復(fù)雜,但是有些坑,很多已經(jīng)忘記了。
印象深刻的是我說自己熟悉常用設(shè)計模式,然后讓我畫UML類圖,我就懵逼了,所以在寫簡歷的時候,最好是寫自己非常熟悉的,如果只是一知半解,并沒有必要放到簡歷中。
公司3:
這里僅列舉幾個問到的問題:
1、設(shè)計一個中繼服務(wù)器,轉(zhuǎn)發(fā)客戶A->客戶B的請求;
2、myisam跟innodb有什么區(qū)別;
3、php進程死鎖產(chǎn)生的原因是什么?怎么自動排查與自動恢復(fù)?
4、有class A { public function b($a, $b, $c){}};
怎么使用['b' => 2, 'a' => 1, 'c' => 3],對進行A::b進行調(diào)用,并順利賦值?
5、php5.2->php7.1的各版本演進歷史,新增特性等?
6、畫一個tcp三次握手圖
在我看來8年的程序員怎么也不應(yīng)該是這樣子的,溫水煮青蛙的教訓(xùn)非常慘痛,招招打在要害才知道疼,好在現(xiàn)在認識到問題還不晚,等到了35歲這個年紀(jì),可能就真的晚了.
總結(jié)
以上是生活随笔為你收集整理的八年phper的高级工程师面试之路八年phper的高级工程师面试之路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陈天奇《Introduction to
- 下一篇: QT水费管理系统 ——纯C++开发