簡(jiǎn)書(shū) 占小狼
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝!
如果讀完覺(jué)得有收獲的話,歡迎點(diǎn)贊加關(guān)注
愿你被這個(gè)世界溫柔以待

從《關(guān)于Java面試,你應(yīng)該準(zhǔn)備這些知識(shí)點(diǎn)》 一文的閱讀量和點(diǎn)贊程度可以發(fā)現(xiàn),貌似大家更喜歡這類(lèi)文章,也許是技術(shù)型的文章看著比較的枯燥,這些只是我近段時(shí)間求職面試時(shí)所遇到的一些問(wèn)題,整理出來(lái)希望對(duì)有需要的同學(xué)提供幫助,可以更系統(tǒng)的去學(xué)習(xí)各個(gè)知識(shí)點(diǎn)。
虛擬機(jī)JVM相關(guān)
這塊內(nèi)容并非每個(gè)面試官都會(huì)問(wèn),但是如果是應(yīng)聘高級(jí)職位的話,這一環(huán)節(jié)是不可缺少的,面試的難易程度也不一樣,有些面試官或許讓你講講虛擬機(jī)的內(nèi)存模型即可,有些也會(huì)讓你解釋垃圾回收的實(shí)現(xiàn),當(dāng)然也會(huì)有虛擬機(jī)調(diào)優(yōu)的實(shí)戰(zhàn)經(jīng)驗(yàn),線上問(wèn)題排查等等。
場(chǎng)景對(duì)話:
面試官:Java虛擬機(jī)有了解么?
我:恩,略有接觸過(guò)...(水哥說(shuō)過(guò),話不能說(shuō)太滿,容易打臉)
面試官:那你先講講它的內(nèi)存模型吧
我:Java堆,Java棧,程序計(jì)數(shù)器,方法區(qū),1.7的永久代,1.8的metaspace....(噼里啪啦概念講一通,簡(jiǎn)短描述下每個(gè)內(nèi)存區(qū)的用途,能想到的都講出來(lái),不要保留,不要等面試官問(wèn) “還有嗎?”)
面試官:好,一般Java堆是如何實(shí)現(xiàn)的?
我:在HotSpot虛擬機(jī)實(shí)現(xiàn)中,Java堆分成了新生代和老年代,我當(dāng)時(shí)看的是1.7的實(shí)現(xiàn),所有還有永久代,新生代中又分為了eden區(qū)和survivor區(qū),survivor區(qū)又分成了S0和S1,或則是from和to,(這個(gè)時(shí)候,我要求紙和筆,因?yàn)槲矣X(jué)得這個(gè)話題可以聊蠻長(zhǎng)時(shí)間,又是我比較熟悉的...一邊畫(huà)圖,一邊描述),其中eden,from和to的內(nèi)存大小默認(rèn)是8:1:1(各種細(xì)節(jié)都要說(shuō)出來(lái)...),此時(shí),我已經(jīng)在紙上畫(huà)出了新生代和老年代代表的區(qū)域
面試官:恩,給我講講對(duì)象在內(nèi)存中的初始化過(guò)程?
我:(千萬(wàn)不要只說(shuō),新對(duì)象在Java堆進(jìn)行內(nèi)存分配并初始化,或是在eden區(qū)進(jìn)行內(nèi)存分配并初始化)要初始化一個(gè)對(duì)象,首先要加載該對(duì)象所對(duì)應(yīng)的class文件,該文件的數(shù)據(jù)會(huì)被加載到永久代,并創(chuàng)建一個(gè)底層的instanceKlass對(duì)象代表該class,再為將要初始化的對(duì)象分配內(nèi)存空間,優(yōu)先在線程私有內(nèi)存空間中分配大小,如果空間不足,再到eden中進(jìn)行內(nèi)存分配...^&&*%
面試官:恩,好,說(shuō)下YGC的大概過(guò)程...
我:先找出根對(duì)象,如Java棧中引用的對(duì)象、靜態(tài)變量引用的對(duì)象和系統(tǒng)詞典中引用的對(duì)象等待,把這些對(duì)象標(biāo)記成活躍對(duì)象,并復(fù)制到to區(qū),接著遍歷這些活躍對(duì)象中引用的對(duì)象并標(biāo)記,找出老年代對(duì)象在eden區(qū)有引用關(guān)系的對(duì)象并標(biāo)記,最后把這些標(biāo)記的對(duì)象復(fù)制到to,在復(fù)制過(guò)程還要判斷活躍對(duì)象的gc年齡是否已經(jīng)達(dá)到閾值,如果已經(jīng)達(dá)到閾值,就直接晉升到老年代,YGC結(jié)束之后把from和to的引用互換(能多說(shuō)點(diǎn)就多說(shuō)點(diǎn),省的面試官再提問(wèn),我把老年代的cms回收也大致說(shuō)了一遍,以為面試官會(huì)跳過(guò)這個(gè)話題了,還是太年輕了)。
面試官:你剛剛說(shuō)到在YGC的時(shí)候,有些對(duì)象可能會(huì)發(fā)生晉升,如果晉升失敗怎么處理?
我:....(斷片了幾秒鐘,我記得我分析過(guò)這段代碼的,但是印象不深刻了)我記得在標(biāo)記階段時(shí),會(huì)把對(duì)象和對(duì)應(yīng)的對(duì)象頭數(shù)據(jù)保存在兩個(gè)棧中,如果晉升失敗的話,就把該對(duì)象的對(duì)象頭復(fù)原...
面試官:那你在實(shí)際項(xiàng)目中有碰到這種情況么,會(huì)導(dǎo)致什么問(wèn)題?
我:...(這我真沒(méi)有遇到過(guò))對(duì),有遇到過(guò)一次,在分析gc日志的時(shí)候,發(fā)現(xiàn)YGC發(fā)生之后,日志顯示gc后的內(nèi)存變大了,后來(lái)查出來(lái)是因?yàn)閷?duì)象的晉升失敗造成的。(我隱約記得看過(guò)笨神的一篇文章,回答的心里很虛)
面試官:(沒(méi)有反駁,繼續(xù)問(wèn))有過(guò)虛擬機(jī)性能調(diào)優(yōu)的經(jīng)驗(yàn)么?
我:(說(shuō)實(shí)話,調(diào)優(yōu)經(jīng)驗(yàn)真的不多)恩,有一點(diǎn)吧,不是很足,就是我們XX項(xiàng)目上線的時(shí)候,發(fā)現(xiàn)YGC特別的頻繁^&8&,通過(guò)調(diào)整新生代的大?。ň€上環(huán)境的虛擬機(jī)參數(shù)是默認(rèn)的),同時(shí)檢查業(yè)務(wù)邏輯代碼&*&$$~~!
面試官:恩?還有么?
我:(面試這么久,好怕面試官的下一句是 “恩?還有么?”,顯然面試官還不滿足我的回答,但是我也只能答到這個(gè)地步了...)恩,經(jīng)驗(yàn)確實(shí)有限,目前就根據(jù)這個(gè)項(xiàng)目做過(guò)一些相關(guān)的優(yōu)化。
面試官: 。。。。。。
我:。。。。。。
面試官: 那我們看看別的吧。
關(guān)于虛擬機(jī)方面的文章,我針對(duì)hotSpot的實(shí)現(xiàn)寫(xiě)了一些分析,感興趣的同學(xué)可以看看,這些文章看著確實(shí)有點(diǎn)枯燥。
相關(guān)文章:
JVM源碼分析之JVM啟動(dòng)流程
JVM源碼分析之堆內(nèi)存的初始化
JVM源碼分析之Java類(lèi)的加載過(guò)程
JVM源碼分析之Java對(duì)象的創(chuàng)建過(guò)程
JVM源碼分析之如何觸發(fā)并執(zhí)行GC線程
JVM源碼分析之垃圾收集的執(zhí)行過(guò)程
JVM源碼分析之新生代DefNewGeneration的實(shí)現(xiàn)
JVM源碼分析之老年代TenuredGeneration的垃圾回收算法實(shí)現(xiàn)
細(xì)節(jié)問(wèn)題
細(xì)節(jié)決定成敗,在面試過(guò)程中,雖然也有運(yùn)氣的成分存在,但是對(duì)于細(xì)節(jié)的掌握程度,可以很好的衡量應(yīng)試者的技術(shù)水平。
volatile
場(chǎng)景對(duì)話:
面試官:說(shuō)說(shuō)volatile關(guān)鍵字的實(shí)現(xiàn)原理
我:volatile關(guān)鍵字提供了內(nèi)存可見(jiàn)性和禁止內(nèi)存重排序
面試官:分別解釋一下
我:因?yàn)樵谔摂M機(jī)內(nèi)存中有主內(nèi)存和工作內(nèi)存的概念,每個(gè)cpu都有自己的工作內(nèi)存,當(dāng)讀取一個(gè)普通變量時(shí),優(yōu)先讀取工作內(nèi)存的變量,如果工作內(nèi)存中沒(méi)有對(duì)應(yīng)的變量,則從主內(nèi)存中加載到工作內(nèi)存,對(duì)工作內(nèi)存的普通變量進(jìn)行修改,不會(huì)立馬同步到主內(nèi)存,內(nèi)存可見(jiàn)性保證了在多線程的場(chǎng)景下,保證了線程A對(duì)變量的修改,其它線程可以讀到最新值&&%%……
面試官:如何保證的?
我:當(dāng)對(duì)volatile修飾的變量進(jìn)行寫(xiě)操作時(shí),直接把最新值寫(xiě)到主內(nèi)存中,并清空其它c(diǎn)pu工作內(nèi)存中該變量所在的內(nèi)存行數(shù)據(jù),當(dāng)對(duì)volatile修飾的變量進(jìn)行讀操作時(shí),會(huì)讀取主內(nèi)存的數(shù)據(jù)&&&%%¥@
面試官:你知道系統(tǒng)級(jí)別是如何實(shí)現(xiàn)的么?
我:(what,what are u 說(shuō)啥呢)我記得操作volatile變量的匯編代碼前面會(huì)有lock前綴指令
面試官:你這說(shuō)的還是代碼層面,我說(shuō)的是系統(tǒng)級(jí)別
我:(懵逼臉...)這個(gè)再底層下去我真的沒(méi)研究過(guò)了...
相關(guān)文章:《java volatile關(guān)鍵字解惑》
Object.finalize
場(chǎng)景對(duì)話:
面試官:和我講講Object類(lèi)的finalize方法的實(shí)現(xiàn)原理
我:(完全沒(méi)想到面試官會(huì)問(wèn)這個(gè))新建一個(gè)對(duì)象時(shí),在JVM中會(huì)判斷該對(duì)象對(duì)應(yīng)的類(lèi)是否重寫(xiě)了finalize方法,且finalize方法體不為空,則把該對(duì)象封裝成Finalizer對(duì)象,并添加到Finalizer鏈表。
面試官:恩,然后呢?
我:Finalizer類(lèi)中會(huì)初始化一個(gè)FinalizerThread類(lèi)型的線程,負(fù)責(zé)從一個(gè)引用隊(duì)列中獲取Finalizer對(duì)象,并執(zhí)行該Finalizer對(duì)象的runFinalizer方法,最終會(huì)執(zhí)行原始對(duì)象的finalize方法,&&%%##(這塊邏輯有點(diǎn)繞,當(dāng)時(shí)答的也有點(diǎn)虛)
面試官:Finalizer對(duì)象什么時(shí)候會(huì)在引用隊(duì)列中?
我:(努力回想中)在發(fā)生GC的時(shí)候,具體在什么時(shí)間點(diǎn)或如何被插入到引用隊(duì)列中,這塊實(shí)現(xiàn)我已經(jīng)忘記了...(我真的忘記了,只記得這塊邏輯太復(fù)雜了)
面試官:恩,你驗(yàn)證過(guò)finalize方法是否會(huì)執(zhí)行么?
我:恩,自己寫(xiě)過(guò)例子證明過(guò),也看過(guò)源碼的實(shí)現(xiàn)。
面試官:怎么證明的?
我:初始化一個(gè)大數(shù)組,可以明顯看出gc之后是否被回收,然后執(zhí)行System.gc(),在finalize方法中輸出信息 &&%%@@,(把之前做過(guò)的驗(yàn)證說(shuō)一遍)
面試官:恩,可以...
相關(guān)文章: 《深入分析Object.finalize方法的實(shí)現(xiàn)原理》
大問(wèn)題
什么是大問(wèn)題,就是問(wèn)題很大,讓你自己去理解,把你的畢生所學(xué)都拿出來(lái).
場(chǎng)景對(duì)話:
面試官:如果給你一個(gè)系統(tǒng),如何去優(yōu)化?
我:(優(yōu)化什么?性能,穩(wěn)定性,還是其它方面,只能硬著頭皮上了,結(jié)合自己做的一個(gè)項(xiàng)目)
1、分析系統(tǒng),定義指標(biāo)
2、通過(guò)系統(tǒng)埋點(diǎn),收集指標(biāo)的度量值,對(duì)指標(biāo)進(jìn)行迭代優(yōu)化&&^%&$#
面試官:就這些?沒(méi)了么?
我:(因?yàn)槭请娫捗嬖?,感覺(jué)當(dāng)時(shí)腦袋是空白的,估計(jì)和面試官的級(jí)別也有關(guān)系)如果指標(biāo)是接口性能的話,可以看下系統(tǒng)內(nèi)存是不是可以使用緩存進(jìn)行性能上的優(yōu)化,比如redis,如果是訪問(wèn)很頻繁又不會(huì)經(jīng)常變動(dòng)的數(shù)據(jù),如熱點(diǎn)數(shù)據(jù),可以直接使用本地緩存進(jìn)行優(yōu)化,畢竟一次網(wǎng)絡(luò)請(qǐng)求也需要1~2毫秒
面試官:沒(méi)了么?
我:(因?yàn)樽约合到y(tǒng)優(yōu)化的經(jīng)驗(yàn)確實(shí)不豐富,讓面試官覺(jué)得怎么就只能想到如此少的優(yōu)化點(diǎn)呢)數(shù)據(jù)庫(kù)的讀寫(xiě)分離,數(shù)據(jù)庫(kù)的分庫(kù)分表,如果經(jīng)常條件查詢數(shù)據(jù)庫(kù)的話,可以引入搜索服務(wù)es或則lucene進(jìn)行優(yōu)化