從《關於Java面試,你應該準備這些知識點》 一文的閱讀量和點贊程度能夠發現,貌似你們更喜歡這類文章,也許是技術型的文章看着比較的枯燥,這些只是我近段時間求職面試時所遇到的一些問題,整理出來但願對有須要的同窗提供幫助,能夠更系統的去學習各個知識點。java
這塊內容並不是每一個面試官都會問,可是若是是應聘高級職位的話,這一環節是不可缺乏的,面試的難易程度也不同,有些面試官或許讓你講講虛擬機的內存模型便可,有些也會讓你解釋垃圾回收的實現,固然也會有虛擬機調優的實戰經驗,線上問題排查等等。面試
場景對話:
面試官:Java虛擬機有了解麼?redis
我:恩,略有接觸過...(水哥說過,話不能說太滿,容易打臉)算法
面試官:那你先講講它的內存模型吧數據庫
我:Java堆,Java棧,程序計數器,方法區,1.7的永久代,1.8的metaspace....(噼裏啪啦概念講一通,簡短描述下每一個內存區的用途,能想到的都講出來,不要保留,不要等面試官問 「還有嗎?」)數組
面試官:好,通常Java堆是如何實現的?緩存
我:在HotSpot虛擬機實現中,Java堆分紅了新生代和老年代,我當時看的是1.7的實現,全部還有永久代,新生代中又分爲了eden區和survivor區,survivor區又分紅了S0和S1,或則是from和to,(這個時候,我要求紙和筆,由於我以爲這個話題能夠聊蠻長時間,又是我比較熟悉的...一邊畫圖,一邊描述),其中eden,from和to的內存大小默認是8:1:1(各類細節都要說出來...),此時,我已經在紙上畫出了新生代和老年代表明的區域網絡
面試官:恩,給我講講對象在內存中的初始化過程?多線程
我:(千萬不要只說,新對象在Java堆進行內存分配並初始化,或是在eden區進行內存分配並初始化)要初始化一個對象,首先要加載該對象所對應的class文件,該文件的數據會被加載到永久代,並建立一個底層的instanceKlass對象表明該class,再爲將要初始化的對象分配內存空間,優先在線程私有內存空間中分配大小,若是空間不足,再到eden中進行內存分配...^&&*%ide
面試官:恩,好,說下YGC的大概過程...
我:先找出根對象,如Java棧中引用的對象、靜態變量引用的對象和系統詞典中引用的對象等待,把這些對象標記成活躍對象,並複製到to區,接着遍歷這些活躍對象中引用的對象並標記,找出老年代對象在eden區有引用關係的對象並標記,最後把這些標記的對象複製到to,在複製過程還要判斷活躍對象的gc年齡是否已經達到閾值,若是已經達到閾值,就直接晉升到老年代,YGC結束以後把from和to的引用互換(能多說點就多說點,省的面試官再提問,我把老年代的cms回收也大體說了一遍,覺得面試官會跳過這個話題了,仍是太年輕了)。
面試官:你剛剛說到在YGC的時候,有些對象可能會發生晉升,若是晉升失敗怎麼處理?
我:....(斷片了幾秒鐘,我記得我分析過這段代碼的,可是印象不深入了)我記得在標記階段時,會把對象和對應的對象頭數據保存在兩個棧中,若是晉升失敗的話,就把該對象的對象頭復原...
面試官:那你在實際項目中有碰到這種狀況麼,會致使什麼問題?
我:...(這我真沒有遇到過)對,有遇到過一次,在分析gc日誌的時候,發現YGC發生以後,日誌顯示gc後的內存變大了,後來查出來是由於對象的晉升失敗形成的。(我隱約記得看過笨神的一篇文章,回答的內心很虛)
面試官:(沒有反駁,繼續問)有過虛擬機性能調優的經驗麼?
我:(說實話,調優經驗真的很少)恩,有一點吧,不是很足,就是咱們XX項目上線的時候,發現YGC特別的頻繁^^&^8&,經過調整新生代的大小(線上環境的虛擬機參數是默認的),同時檢查業務邏輯代碼&*&$$~~!
面試官:恩?還有麼?
我:(面試這麼久,好怕面試官的下一句是 「恩?還有麼?」,顯然面試官還不知足個人回答,可是我也只能答到這個地步了...)恩,經驗確實有限,目前就根據這個項目作過一些相關的優化。
面試官: 。。。。。。
我:。。。。。。
面試官: 那咱們看看別的吧。
關於虛擬機方面的文章,我針對hotSpot的實現寫了一些分析,感興趣的同窗能夠看看,這些文章看着確實有點枯燥。
相關文章:
JVM源碼分析之JVM啓動流程
JVM源碼分析之堆內存的初始化
JVM源碼分析之Java類的加載過程
JVM源碼分析之Java對象的建立過程
JVM源碼分析之如何觸發並執行GC線程
JVM源碼分析之垃圾收集的執行過程
JVM源碼分析之新生代DefNewGeneration的實現
JVM源碼分析之老年代TenuredGeneration的垃圾回收算法實現
細節決定成敗,在面試過程當中,雖然也有運氣的成分存在,可是對於細節的掌握程度,能夠很好的衡量應試者的技術水平。
場景對話:
面試官:說說volatile關鍵字的實現原理
我:volatile關鍵字提供了內存可見性和禁止內存重排序
面試官:分別解釋一下
我:由於在虛擬機內存中有主內存和工做內存的概念,每一個cpu都有本身的工做內存,當讀取一個普通變量時,優先讀取工做內存的變量,若是工做內存中沒有對應的變量,則從主內存中加載到工做內存,對工做內存的普通變量進行修改,不會立馬同步到主內存,內存可見性保證了在多線程的場景下,保證了線程A對變量的修改,其它線程能夠讀到最新值&&%%……
面試官:如何保證的?
我:當對volatile修飾的變量進行寫操做時,直接把最新值寫到主內存中,並清空其它cpu工做內存中該變量所在的內存行數據,當對volatile修飾的變量進行讀操做時,會讀取主內存的數據&&&%%¥@
面試官:你知道系統級別是如何實現的麼?
我:(what,what are u 說啥呢)我記得操做volatile變量的彙編代碼前面會有lock前綴指令
面試官:你這說的仍是代碼層面,我說的是系統級別
我:(懵逼臉...)這個再底層下去我真的沒研究過了...
相關文章:《java volatile關鍵字解惑》
場景對話:
面試官:和我講講Object類的finalize方法的實現原理
我:(徹底沒想到面試官會問這個)新建一個對象時,在JVM中會判斷該對象對應的類是否重寫了finalize方法,且finalize方法體不爲空,則把該對象封裝成Finalizer對象,並添加到Finalizer鏈表。
面試官:恩,而後呢?
我:Finalizer類中會初始化一個FinalizerThread類型的線程,負責從一個引用隊列中獲取Finalizer對象,並執行該Finalizer對象的runFinalizer方法,最終會執行原始對象的finalize方法,&&%%##(這塊邏輯有點繞,當時答的也有點虛)
面試官:Finalizer對象何時會在引用隊列中?
我:(努力回想中)在發生GC的時候,具體在什麼時間點或如何被插入到引用隊列中,這塊實現我已經忘記了...(我真的忘記了,只記得這塊邏輯太複雜了)
面試官:恩,你驗證過finalize方法是否會執行麼?
我:恩,本身寫過例子證實過,也看過源碼的實現。
面試官:怎麼證實的?
我:初始化一個大數組,能夠明顯看出gc以後是否被回收,而後執行System.gc(),在finalize方法中輸出信息 &&%%@@,(把以前作過的驗證說一遍)
面試官:恩,能夠...
相關文章: 《深刻分析Object.finalize方法的實現原理》
什麼是大問題,就是問題很大,讓你本身去理解,把你的畢生所學都拿出來.
場景對話:
面試官:若是給你一個系統,如何去優化?
我:(優化什麼?性能,穩定性,仍是其它方面,只能硬着頭皮上了,結合本身作的一個項目)
一、分析系統,定義指標
二、經過系統埋點,收集指標的度量值,對指標進行迭代優化&&^%&$#
面試官:就這些?沒了麼?
我:(由於是電話面試,感受當時腦殼是空白的,估計和麪試官的級別也有關係)若是指標是接口性能的話,能夠看下系統內存是否是可使用緩存進行性能上的優化,好比redis,若是是訪問很頻繁又不會常常變更的數據,如熱點數據,能夠直接使用本地緩存進行優化,畢竟一次網絡請求也須要1~2毫秒
面試官:沒了麼?
我:(由於本身系統優化的經驗確實不豐富,讓面試官以爲怎麼就只能想到如此少的優化點呢)數據庫的讀寫分離,數據庫的分庫分表,若是常常條件查詢數據庫的話,能夠引入搜索服務es或則lucene進行優化