本文轉載自:https://juejin.cn/post/696426556988955034,作者:yjy239
Hello,大家好,我是魚哥。最近很多人找工作,反饋能否多發些面經相關的文章,幫助大家找工作助力。分享一個老鐵,最近面試的面經。以下文中的我均指的是原作者。話不多說,進入正題。
這段時間稍微斷更了一段時間,因為我在準備面試。經過兩次面試後,有一些比較深刻的認識。對於大廠來說,除了對專業知識考究之外,對演算法也尤為看重。
簡單的說一下情況,位元組已經拿到offer,騰訊所有的面面試已經通過了,也應該有offer了。位元組一共4面:3面技術,1面hr;騰訊5次技術面,1次hr面。其中5面是2個面試官上陣。
總的來說騰訊的面試確實強度更高更加持久。位元組是分開一次1個小時面試的。而騰訊1、2面是一次一小時,而3面和4面是連續面試一口氣高強度的面試2小時,5面則是2個面試官輪流提問。騰訊是持久戰稍微腦子不清醒一點就可能出現大錯漏。我在4面就是如此,差點出事了。請準備好糖分和水分及時補充,或者洗把臉保持清晰。
面試的過程一般只有1個小時,如何在一個小時內徹底的考究你本人的水平究竟到達那種境界,也是面試官努力的方向。
而面試往往是由兩部分構成:
1.演算法
2.專業知識
2.專業知識
關於演算法
為什麼把演算法擺在第一點,因為演算法在我看來這是大部分沒有面試過大廠的朋友可能會忽視的一方面。它的重要程度不比專業知識的考究來的低。
在1-2小時內,如何能快速的看到你編碼水平和思維就看這些演算法的考究。
因此需要對常見的資料結構比較熟悉,如連結串列,樹,棧,堆。需要知道遇到陣列相關的題型可能需要用到如快慢指標等解題思路。還有廣度深度優先演算法。最後,如果還有更難一點的,會涉及到回溯,動態規劃等解題思路。
前面幾點都比較好處理,只要在leetcode上做到一定量的題目,都能反應過來。我本人認為我並非是聰明的人,做了300快400道題也僅僅只是摸索出了一些大致的套路。我是完全比不了那些做了100+道題就能靈活掌握演算法的大神。但是經過了系統性的訓練,遇到一些常見的演算法解題思路可以快速的反應過來。
而動態規劃相關的問題,我看來是最難的。關鍵是需要判斷題目是否可以分解成小問題且小問題之間不能互相影響,接著找到動態規劃方程,或者是狀態轉移表。
在聽到面試官的演算法題後,先不要急著下筆。最好在下筆之前和麵試官聊聊你的思路。不同面試官的要求不同,有的面試官,希望演算法是原地演算法,有的面試官希望時間複雜度降低,有的希望空間複雜度降低。
最好能清晰的表達你的初步思路後,面試官會知道你的演算法的方向是否正確,可以一定程度上給予你方向上的指引。
記住就算你做過原題,除非你的方案能保證是從空間和時間複雜度是最優,不然我還是建議面試者多和麵試官交流。在交流的過程中,面試官也能明白你的思考過程,從而判斷你這個人的程式設計能力如何。
千萬不要小看這個模組的考究,如果說面試專業知識是100分,那麼演算法題可以佔據50分。如果你寫不出,或者思路完全偏離了,那就可以說再見了。
在我寫文章學習的這5年裡面,也有不少的朋友問我的意向,其中不乏有大廠。然而我深知我的演算法水平確實不太行,學習的原始碼水平還不足,很多時候都婉拒了。也就今年和去年,練習演算法已有近2個年頭,才敢出山試試。
就算是這樣的我,演算法上的能力評價還是不高,只能說是達到了大廠的合格線,還需要繼續加強。
最後,再給兩點建議:
一個人光看不練是不行的,一個人瞎琢磨效率偏低。
最好可以買幾本書或者課程指導。我是看了輝哥的課程,閱讀了極客時間的劉超的資料結構,還閱讀了書籍演算法4。把基礎都補充好後,可以去leetcode中對每一個數據結構專項進行訓練。在這些基礎上,在做一做劍指offer中經典題目也就差不多了。
關於專業知識
網上很多人都在求大廠面試的真題,實際上我看來意義並不大。因為面試官並不會面試你寫在簡歷之外的隨意一個問題。一般都是問你簡歷上的工作成果,以及背後延伸出來的知識點。更多的還是需要自己日常的積累。
當然也有一些老生常談的基本考點,如Handler,多執行緒等。
因此,背面試題不是最重要。關鍵是回顧你的簡歷上的工作成果以及簡歷上的知識點,並不斷的深挖。
下面是面試情況,以及一些簡答。實際上在回答的過程中,可以回答的更加詳細,本文只是篩選了部分問題簡單介紹了知識點的要點。
位元組面試
位元組面試一共4面。位元組的面試風格偏向基礎的內容,以及簡歷上知識點的擴充套件。
位元組1面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
1.自我介紹,專案經歷,專案上的最佳化項以及原因
2.為什麼使用mmap最佳化io讀寫,mmap和傳統讀寫有什麼區別?為什麼選擇它?
簡答大意:mmap本質上從核心中 程序中申請了vm_area_struct虛擬記憶體後,把虛擬記憶體儲存到 file結構體address_space結構體中的i_mmap中。當需要訪問這段虛擬地址,就會產生卻也中斷,透過夥伴系統申請出物理記憶體繫結。如果是檔案對映還會預讀取檔案內容,之後讀取可以命中後續的快取。專案中也有頻繁進行寫入,可以快速的同步到記憶體中。
3.Object 中有什麼方法?簡答:equal,wait等。
4.Object 的equal實現?重寫equal需要注意的方面。簡答:equal 本質上是獲取Object的 hashCode。而在hotspot虛擬機器中,計算方式在類markOop中,hashCode的計算是獲取物件的高16位向右移動16位並且與上掩碼。
equal 重寫時候,需要按需求處理。一般的,為了讓HashMap等需要hashCode計算正確,需要把equal中每一個成員變數。
5.synchronized 原理。簡答:翻譯成位元組碼後,本質上在虛擬機器中對應兩個位元組碼 MONITOR_ENTER 以及 MONITOR_EXIT 。透過Monitor進行臨界區保護。當執行了MONITOR_ENTER後,本質上就會取出Object 中的LockWord 中的記錄鎖狀態資訊。
在Android 虛擬機器中,存在3種鎖。透過記錄thread_id的偏向鎖,瘦鎖,胖鎖。瘦鎖是一種樂觀鎖,本質上就是不斷的自旋讓渡cpu資源。當64次之後獲取不到,則轉化為胖鎖。胖鎖的實現是基於futex 進行同步處理的。
6.volatile原理 簡答:解決三個問題。語序重拍,讀時未同步,寫時被修改。實現原理是基於讀寫欄柵處理cpu讀寫順序,同時處理編譯時候嚴格按照編碼順序處理。本質上是透過c++的atomic實現的。
7.ui最佳化
簡答:最佳化ui層級,activityidleHandler 處理不重要事件,提前例項化ui到快取池子,x2c等,展開說。
8.記憶體最佳化與LeakCanary的原始碼?以及LeakCanary的缺點和如何解決。簡答:LeakCanary 本質上是註冊監聽了四大元件的生命週期,當生命週期銷燬時候,透過一個弱引用包裹該Activity/Fragment 等元件物件,並迴圈檢測該物件是否銷燬了。解決方案,可以透過ReferenceQueue+虛引用。當GC時候會把這些引用物件新增到引用佇列中,接著透過ReferenceDeamon守護執行緒把資料儲存在ReferenceQueue靜態變數中,在ReferenceQueue的poll可以拿到。
9.演算法:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字(Leetcode原題)。位元組2面
1.自我介紹,專案經歷,專案上的最佳化項以及最佳化的原因
1.自我介紹,專案經歷,專案上的最佳化項以及最佳化的原因
2.Rxjava原始碼原理,以及專案中你是如何將Rxjava流進行復用。
簡答:模仿DisposeObserver,當ObservableCreate 呼叫onSubscribe後就會關聯從上流到下流的關係。並透過cas設定到當前執行包的全域性變數中。當第二次使用同一個流呼叫onSubscribe關聯再度關聯,就會dispose當前的rxjava流。只需要處理這一步驟即可。
詳情閱讀Rxjava原始碼解析。
3.你專案中高度自定義了DiskLRUCache。問LRUCache的實現?問LinkedHashMap的實現?問DiskLruCache的實現?問Glide中實現的DiskLruCache的運用。
4.Handler的原理
文章:
handler 解析
handler eventfd解析
handler epoll解析
5.volatile原理
6.synchronize 鎖的轉化流程。
簡答:偏向鎖轉化瘦鎖(owner thread id不一致且沒上鎖),瘦鎖轉化胖鎖(64次獲取不到鎖後)。
7.ReentrantLock 實現。簡答:由AQS(AbstractQueuedSynchronizer)實現。ReentrantLock 分為公平鎖和非公平鎖。AQS本質上是呼叫acquire 時候為本執行緒新增到同步佇列中,每一個執行緒代表一個Node,在每個Node會自旋競爭同步佇列中的狀態。公平鎖需要多一個判斷,就是保證自己是頭節點。
8.ui 最佳化,首屏渲染時機最佳化
9.啟動最佳化,與AlphaManager的實現。
10.插樁的原理以及運用。
ASM
Javapoet
動態代理
11.LiveData 和 ViewModel的原始碼實現
Javapoet
動態代理
11.LiveData 和 ViewModel的原始碼實現
12.x2c 原始碼實現
13.DNS 原理
14.https的原理
13和14可以閱讀 :Android網路程式設計 總覽
13.演算法:判斷一個字串是否是迴文串(注意保證原字串不可改變,可用O(n)的空間複雜度)。方向:棧的考究。
位元組3面 Leader面
1.工作軟技能的考核,以及團隊中的定位
1.工作軟技能的考核,以及團隊中的定位
2.如何進行io 最佳化,指標是什麼,最佳化後的結果以及引數是多少?
方向:可以使用/proc/pid/stat讀取cpu的idle,iowait等。使用mmap最佳化後的結果。
3.演算法:在一個單鏈表中,每k個節點進行反轉,無法被反轉的部分放在末尾。騰訊面試
騰訊的面試風格,普遍是基於你的簡歷上專案經歷,往細節往深處問。我是面試因演算法失敗了一次,後面第二次就成功了。
騰訊的面試風格,普遍是基於你的簡歷上專案經歷,往細節往深處問。我是面試因演算法失敗了一次,後面第二次就成功了。
總結一下2次騰訊面試
騰訊第一次面試1面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
2.ARouter 原始碼實現,專案中對ARouter的擴充套件實現詳細設計
3.ui 最佳化,啟動最佳化,首屏展示時機最佳化
4.volidate 實現
5.Java異常捕獲
13.DNS 原理
14.https的原理
6.jni 中JNIEnv 和執行緒的關係
簡答:執行緒私有,需要JavaVm 重新獲取一個jnienv 呼叫attachThread 方法把執行緒和新的JNIEnv 繫結起來。
7.jni中有幾種註冊native方法。簡答:2種,動態和靜態。關於整個流程中關鍵的資料結構之間的關係可以看下面這篇文章的流程圖:JVM引擎執行總結
8.Native異常捕獲
簡答:透過sigaction儲存系統預設的處理訊號方式,sigaddset 保證一次只關心一種訊號,sigaction 設定自定義的訊號處理方法。在自定義的訊號處理方法中,進行unwind_backtrace 處理,透過_Unwind_GetIP獲得native棧資訊儲存起來,並丟擲異常。同時 當前方法地址 和 so的地址獲取 相對地址,最後透過addr2line 解析 出是so庫中哪一個方法。
簡答:透過sigaction儲存系統預設的處理訊號方式,sigaddset 保證一次只關心一種訊號,sigaction 設定自定義的訊號處理方法。在自定義的訊號處理方法中,進行unwind_backtrace 處理,透過_Unwind_GetIP獲得native棧資訊儲存起來,並丟擲異常。同時 當前方法地址 和 so的地址獲取 相對地址,最後透過addr2line 解析 出是so庫中哪一個方法。
騰訊第一次面試2面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
1.自我介紹,專案經歷,專案上的最佳化項以及原因
2.ARouter的實現,以及自定義擴充套件ARouter的實現
3.專案中的io 最佳化,以及為什麼用mmap於io最佳化
4.mmap的實現
5.mmkv 中 對應 mmap 斷電時候的處理機制
6.mmap沒呼叫msync時候,落盤時機。
簡答:程序死亡
詳情看
Binder 中mmap原理
Binder 總結 內涵mmap系統呼叫解析
mmkv 原始碼解析
6.演算法:合併三個單鏈表(可參考leetcode 合併多個單鏈表)
因為自己畫蛇添足,把每一個節點複製了一次,還沒有往後迭代,實在是錯漏百出就掛了。腦袋還是不夠清醒,結果飲恨而歸。
騰訊第二次面試1面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
2.ARouter 的實現,以及擴充套件的實現
3.啟動最佳化,以及ARouter的啟動最佳化方式,ARouter的分割槽方式
4.Navigation的原始碼解析
5.基於Navigation 編寫路由框架NavigationRouter 的原始碼實現,以及實現的優點
6.Navigation 實現的路由框架中如何處理Activity和Fragment 巢狀啟動的方式
7.class的載入流程
文章:class 檔案初識
8.Handler的實現
文章:
handler 解析
handler eventfd解析
handler epoll解析
最好能回答到epoll和eventfd的層面
handler eventfd解析
handler epoll解析
最好能回答到epoll和eventfd的層面
9.實現一個多執行緒下的消費者生產者模式
騰訊第二次面試2面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
io 最佳化 與 使用mmap的優勢和缺點
3.ARouter 的實現,以及擴充套件的實現
4.多程序實現的路由
5.如何進行多程序的同步呼叫,此時另一個程序還沒有啟動?參考答案:橫向淺析Small,RePlugin兩個外掛化框架 中,RePugin是如何透過CP 進行跨程序同步通訊
騰訊第二次面試2面
1.自我介紹,專案經歷,專案上的最佳化項以及原因
io 最佳化 與 使用mmap的優勢和缺點
3.ARouter 的實現,以及擴充套件的實現
4.多程序實現的路由
5.如何進行多程序的同步呼叫,此時另一個程序還沒有啟動?參考答案:橫向淺析Small,RePlugin兩個外掛化框架 中,RePugin是如何透過CP 進行跨程序同步通訊
6.資料結構中不支援多執行緒的資料結構,如果使用多執行緒操作會造成什麼結構
簡答:如HashMap,ArrayMap等不支援多執行緒保護原子性的資料結構。每一次進行put,get操作的時候,都會對modCount 加一。用於記錄當前操作次數。一旦看是遍歷裡面的元素,會不斷檢查該操作前儲存的modCount 是否和之前的一致。不一致則丟擲ConcurrentModificationException
簡答:如HashMap,ArrayMap等不支援多執行緒保護原子性的資料結構。每一次進行put,get操作的時候,都會對modCount 加一。用於記錄當前操作次數。一旦看是遍歷裡面的元素,會不斷檢查該操作前儲存的modCount 是否和之前的一致。不一致則丟擲ConcurrentModificationException
7.ArrayMap 實現
簡答:ArrayMap 是記憶體最佳化的資料結構。核心是由兩個陣列組成的資料結構。第一個陣列記錄了key對應的hashCode,這個過程會不斷的透過二分法找到hashCode合適的插入位置。獲得的index,index左移動1位是key快取的位置,index左移動1位加1則是value的快取位置。
簡答:ArrayMap 是記憶體最佳化的資料結構。核心是由兩個陣列組成的資料結構。第一個陣列記錄了key對應的hashCode,這個過程會不斷的透過二分法找到hashCode合適的插入位置。獲得的index,index左移動1位是key快取的位置,index左移動1位加1則是value的快取位置。
ArrayMap中的存在一個靜態陣列,用來儲存大小4/8 開闢過的ArrayMap。如果使用該大小的ArrayMap 則直接使用快取。
ArrayMap的擴容,當儲存的資料大小大於等於hash儲存的陣列大小則擴容,小於4擴容位4,大於4小於8擴容成8,如果大於8則擴容成原來的1.5倍。
每一次remove 發現是儲存的資料是當前容器大小的1/3,則壓縮一半。
8.HashMap 與 ArrayMap比較,兩者的優缺點
簡答:
簡答:
資料結構上:
1.ArrayMap 是兩個陣列組成的是為了記憶體最佳化而生;2.HashMap 採用陣列+連結串列+紅黑樹
記憶體最佳化:
記憶體最佳化:
ArrayMap 更加節省記憶體,因為是一個記憶體中連續開闢的陣列,不易產生記憶體碎片
HashMap 以entry的方式儲存key和value,對記憶體的利用率低
效能上:
HashMap 以entry的方式儲存key和value,對記憶體的利用率低
效能上:
Arraymap 查詢時間是O(logN) 級別(二分法),刪除和增加成員需要移動成員,速度慢,小於1000的情況下沒有區別
HashMap 增刪的時間複雜度就是O(1)
HashMap 增刪的時間複雜度就是O(1)
快取機制:
ArrayMap 針對大小4和8的都有快取。避免頻繁GC,兩個快取池的大小上線為10
Hashmap 沒有快取
擴容機制:
Hashmap 沒有快取
擴容機制:
ArrayMap是在容量滿的時機觸發容量擴大至原來的1.5倍,在容量不足1/3時觸發記憶體收縮至原來的0.5倍,更節省的記憶體擴容機制
HashMap是在容量的0.75倍時觸發容量擴大至原來的2倍,且沒有記憶體收縮機制。9.handler 的原理
HashMap是在容量的0.75倍時觸發容量擴大至原來的2倍,且沒有記憶體收縮機制。9.handler 的原理
10.handler 是怎麼進行postDelay 延時操作。
簡答:postDelay 會將延時+當前的時間戳,插入到MessageQueue的合適位置。每一次消費判斷時間到達延時的時間點,再進行消費。
11.當handler 只有一個延時的message時候,Looper中是如何執行。簡答:透過pollOnce 呼叫epoll 進行阻塞。
12.volidate 原理
13.當沒有新增volidate 修飾屬性的時候,資料什麼時候從快取行重新整理到主存。
簡答:當從synchronized 程式碼域離開的時候;當執行緒結束時候;當呼叫synchronized 方法;當第一次訪問執行緒的某個屬性。
文章:執行緒的快取何時重新整理?
14.演算法題:在一個n*n的方格中。有兩種方格,1代表阻塞不能經過,0代表可達。兩點座標,a和b。問a到b的最短路徑。
騰訊第二次面試3面和4面
騰訊3面和4面是聯絡到一起的,這裡一起說了
1.自我介紹,專案經歷,專案上的最佳化項以及原因
2.mmap 實現原理和io最佳化
3.View的繪製流程,從 setContentView 解析xml到View的繪製結束。
設計的內容極多和廣泛,建議看我寫的如下系列文章:
View的繪製流程 (一)View的初始化
View的繪製流程(二) 繪製的準備
View的繪製流程(三) onMeasure
View的繪製流程(四) onLayout
View的繪製流程(五) onDraw
4.硬體渲染流程
View的繪製流程(六) 硬體渲染(上)
View的繪製流程(七) 硬體渲染(下)
5.SurfaceFlinger 在 View繪製流程中扮演的角色
Choregrapher 的工作原理
關於5和6兩個問題可以詳細閱讀系列文章:SurfaceFlinger的概述
關於5和6兩個問題可以詳細閱讀系列文章:SurfaceFlinger的概述
7.OOM 如何最佳化,記憶體爆滿是虛擬記憶體容易先爆掉還是物理記憶體容易,一口氣對映4g的記憶體是否會發生異常。
8.Bitmap 如何最佳化避免OOM,為什麼放在native中bitmap不容易OOM
9.一個程序最多可以使用多少fd
10.你研究過RN和Flutter,RN的渲染機制和Flutter的渲染機制是如何運作的?他們之間區別是什麼?
關於RN和Flutter的文章,之後有機會會和大家分享出來。
目前來說可以去看看gityuan 的部落格,裡面有詳細的介紹了Flutter的通訊流程和渲染流程。
而RN的渲染流程倒是很多相關的文章,建議直接結合文章看最新的原始碼,不是特別的難。
11.外掛化你是如何實現的。詳細可以閱讀橫向淺析Small,RePlugin兩個外掛化框架 這篇文章有詳細的解析了整個hook的原理和流程。
12.演算法1: 將一個int的數字轉化成漢語說法。如10000轉化為一萬。簡答:方向是除餘,除法移動int,並儲存到棧中。然後推出,生成漢語說法
13.演算法2:中國下棋的馬,能否吃掉另一個座標的旗子,請找出座標
簡答:廣度優先演算法,遍歷8個方向。
簡答:廣度優先演算法,遍歷8個方向。
騰訊二次面試5面
本次面試是兩個面試官進行考察,考察的東西偏向網路協議。
1.自我介紹,專案經歷,專案上的最佳化項以及自己開源在GitHub上專案的特點。
2.當遇到弱網路時候的最佳化
簡答:1.HttpDns,並解釋DNS的原理。2.QUIC協議替換TCP協議,介紹QUIC的原理和TCP的區別。3.介面的適當合併,並結合專案的運用方案1
3.當遇到弱網路時候,網路是如何進行檔案重傳
4.當遇到弱網路時候,手機連線上了4g,但是沒有資料流量時候,如何檢測並恢復。
簡答:fb的network-connection的庫有實現。本質上就是透過一個執行緒不斷的輪訓查詢TrafficStatus中的4g+wifi資料的狀態。核心是呼叫了下面兩個Linux命令:
// stats介面提供各個uid在各個網路介面(wlan0, ppp0等)的流量資訊
/proc/net/xt_qtaguid/stats
// iface_stat_fmt介面提供各個介面的彙總流量資訊
proc/net/xt_qtaguid/iface_stat_fmt
/proc/net/xt_qtaguid/stats
// iface_stat_fmt介面提供各個介面的彙總流量資訊
proc/net/xt_qtaguid/iface_stat_fmt
5.當app在播放音影片的時候,需要注意的要點,以及相關的實現。總結
從專業技能考察可以看到,實際上整個面試過程。騰訊面試的會相對仔細一點,技術廣度更加廣一點;而位元組則更加偏向基礎是否紮實。都是從你的簡歷專案,技術點開始詢問,並根據你回答的問題,不斷的調整詢問的方向,不斷的向下挖你的知識點,看能達到什麼程度
從專業技能考察可以看到,實際上整個面試過程。騰訊面試的會相對仔細一點,技術廣度更加廣一點;而位元組則更加偏向基礎是否紮實。都是從你的簡歷專案,技術點開始詢問,並根據你回答的問題,不斷的調整詢問的方向,不斷的向下挖你的知識點,看能達到什麼程度
但是無論如何,你回答的層面最好足夠深,從原始碼層級說起來。有時候面試官的對問題的看法和你的看法有分歧,此時就需要你是否可以從原始碼的層面上對這些問題有自己的解釋。
面試的專業難度沒有想象的困難,可以看到大部分的知識都是我在重學系列和往年寫的第三方庫的分析都有覆蓋。
而這些知識我寫出來花了3年,實際上學進去就不需要。可以說大部分人都能達到的水平,因此面試的時候只需要沉著冷靜的思考,從原始碼的角度對面試官丟擲來問題進行分析,就能比較輕鬆的解決。
最後有人好奇我去了哪裡。應該是去騰訊。