2020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案(史上最全)

前言:最近老是收到小伙伴的私信問我能不能幫忙整理出一份JVM相關(guān)的面試題出來,說自己在大廠去面試的時候這一塊問的是特別多的,每次自己學(xué)的時候每次都學(xué)不到重點去。這不他來了,一份詳細(xì)的JVM面試真題給大家整理在下方了!
一、什么情況下會發(fā)生棧內(nèi)存溢出?
1、棧是線程私有的,棧的生命周期和線程一樣,每個方法在執(zhí)行的時候就會創(chuàng)建一個棧幀,它包含局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息,局部變量表又包括基本數(shù)據(jù)類型和對象的引用;
2、當(dāng)線程請求的棧深度超過了虛擬機允許的最大深度時,會拋出StackOverFlowError異常,方法遞歸調(diào)用肯可能會出現(xiàn)該問題;
3、調(diào)整參數(shù)-xss去調(diào)整jvm棧的大小
二、詳解JVM內(nèi)存模型?
jvm將虛擬機分為5大區(qū)域,程序計數(shù)器、虛擬機棧、本地方法棧、java堆、方法區(qū);
程序計數(shù)器:線程私有的,是一塊很小的內(nèi)存空間,作為當(dāng)前線程的行號指示器,用于記錄當(dāng)前虛擬機正在執(zhí)行的線程指令地址;
虛擬機棧:線程私有的,每個方法執(zhí)行的時候都會創(chuàng)建一個棧幀,用于存儲局部變量表、操作數(shù)、動態(tài)鏈接和方法返回等信息,當(dāng)線程請求的棧深度超過了虛擬機允許的最大深度時,就會拋出StackOverFlowError;
本地方法棧:線程私有的,保存的是native方法的信息,當(dāng)一個jvm創(chuàng)建的線程調(diào)用native方法后,jvm不會在虛擬機棧中為該線程創(chuàng)建棧幀,而是簡單的動態(tài)鏈接并直接調(diào)用該方法;
堆:java堆是所有線程共享的一塊內(nèi)存,幾乎所有對象的實例和數(shù)組都要在堆上分配內(nèi)存,因此該區(qū)域經(jīng)常發(fā)生垃圾回收的操作;
方法區(qū):存放已被加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼數(shù)據(jù)。即永久代,在jdk1.8中不存在方法區(qū)了,被元數(shù)據(jù)區(qū)替代了,原方法區(qū)被分成兩部分;1:加載的類信息,2:運行時常量池;加載的類信息被保存在元數(shù)據(jù)區(qū)中,運行時常量池保存在堆中;
三、JVM中一次完整的GC是什么樣子的?對象如何晉升到老年代?
java堆 = 新生代+老年代;
新生代 = Eden + Suivivor(S0 + S1),默認(rèn)分配比例是8:1:1;
當(dāng)Eden區(qū)空間滿了的時候,就會觸發(fā)一次Minor GC,以收集新生代的垃圾,存活下來的對象會被分配到Survivor區(qū)
大對象(需要大量連續(xù)內(nèi)存空間的對象)會直接被分配到老年代
如果對象在Eden中出生,并且在經(jīng)歷過一次Minor GC之后仍然存活,被分配到存活區(qū)的話,年齡+1,此后每經(jīng)歷過一次Minor GC并且存活下來,年齡就+1,當(dāng)年齡達(dá)到15的時候,會被晉升到老年代;
當(dāng)老年代滿了,而無法容納更多對象的話,會觸發(fā)一次full gc;full gc存儲的是整個內(nèi)存堆(包括年輕代和老年代);;
Major GC是發(fā)生在老年代的GC,清理老年區(qū),經(jīng)常會伴隨至少一次minor gc;
四、Java中的垃圾回收算法?
java中有四種垃圾回收算法,分別是標(biāo)記清除法、標(biāo)記整理法、復(fù)制算法、分代收集算法;
標(biāo)記清除法:
第一步:利用可達(dá)性去遍歷內(nèi)存,把存活對象和垃圾對象進(jìn)行標(biāo)記;
第二步:在遍歷一遍,將所有標(biāo)記的對象回收掉;
特點:效率不行,標(biāo)記和清除的效率都不高;標(biāo)記和清除后會產(chǎn)生大量的不連續(xù)的空間分片,可能會導(dǎo)致之后程序運行的時候需分配大對象而找不到連續(xù)分片而不得不觸發(fā)一次GC;
標(biāo)記整理法:
第一步:利用可達(dá)性去遍歷內(nèi)存,把存活對象和垃圾對象進(jìn)行標(biāo)記;
第二步:將所有的存活的對象向一段移動,將端邊界以外的對象都回收掉;
特點:適用于存活對象多,垃圾少的情況;需要整理的過程,無空間碎片產(chǎn)生;
復(fù)制算法:
將內(nèi)存按照容量大小分為大小相等的兩塊,每次只使用一塊,當(dāng)一塊使用完了,就將還存活的對象移到另一塊上,然后在把使用過的內(nèi)存空間移除;
特點:不會產(chǎn)生空間碎片;內(nèi)存使用率極低;
分代收集算法:
根據(jù)內(nèi)存對象的存活周期不同,將內(nèi)存劃分成幾塊,java虛擬機一般將內(nèi)存分成新生代和老生代,在新生代中,有大量對象死去和少量對象存活,所以采用復(fù)制算法,只需要付出少量存活對象的復(fù)制成本就可以完成收集;老年代中因為對象的存活率極高,沒有額外的空間對他進(jìn)行分配擔(dān)保,所以采用標(biāo)記清理或者標(biāo)記整理算法進(jìn)行回收;
五、如何判斷一個對象是否存活?
判斷一個對象是否存活,分為兩種算法1:引用計數(shù)法;2:可達(dá)性分析算法;
引用計數(shù)法:
給每一個對象設(shè)置一個引用計數(shù)器,當(dāng)有一個地方引用該對象的時候,引用計數(shù)器就+1,引用失效時,引用計數(shù)器就-1;當(dāng)引用計數(shù)器為0的時候,就說明這個對象沒有被引用,也就是垃圾對象,等待回收;
缺點:無法解決循環(huán)引用的問題,當(dāng)A引用B,B也引用A的時候,此時AB對象的引用都不為0,此時也就無法垃圾回收,所以一般主流虛擬機都不采用這個方法;
可達(dá)性分析法
從一個被稱為GC Roots的對象向下搜索,如果一個對象到GC Roots沒有任何引用鏈相連接時,說明此對象不可用,在java中可以作為GC Roots的對象有以下幾種:
虛擬機棧中引用的對象
方法區(qū)類靜態(tài)屬性引用的變量
方法區(qū)常量池引用的對象
本地方法棧JNI引用的對象
但一個對象滿足上述條件的時候,不會馬上被回收,還需要進(jìn)行兩次標(biāo)記;第一次標(biāo)記:判斷當(dāng)前對象是否有finalize()方法并且該方法沒有被執(zhí)行過,若不存在則標(biāo)記為垃圾對象,等待回收;若有的話,則進(jìn)行第二次標(biāo)記;第二次標(biāo)記將當(dāng)前對象放入F-Queue隊列,并生成一個finalize線程去執(zhí)行該方法,虛擬機不保證該方法一定會被執(zhí)行,這是因為如果線程執(zhí)行緩慢或進(jìn)入了死鎖,會導(dǎo)致回收系統(tǒng)的崩潰;如果執(zhí)行了finalize方法之后仍然沒有與GC Roots有直接或者間接的引用,則該對象會被回收;
六、有哪幾種垃圾回收器,有哪些優(yōu)缺點?cms和g1的區(qū)別?
垃圾回收器主要分為以下幾種:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;
Serial:
單線程的收集器,收集垃圾時,必須stop the world,使用復(fù)制算法。
ParNew:
Serial收集器的多線程版本,也需要stop the world,復(fù)制算法.
Parallel Scavenge:
新生代收集器,復(fù)制算法的收集器,并發(fā)的多線程收集器,目標(biāo)是達(dá)到一個可控的吞吐量,和ParNew的最大區(qū)別是GC自動調(diào)節(jié)策略;虛擬機會根據(jù)系統(tǒng)的運行狀態(tài)收集性能監(jiān)控信息,動態(tài)設(shè)置這些參數(shù),以提供最優(yōu)停頓時間和最高的吞吐量;
Serial Old:
Serial收集器的老年代版本,單線程收集器,使用標(biāo)記整理算法。
Parallel Old:
是Parallel Scavenge收集器的老年代版本,使用多線程,標(biāo)記-整理算法。
CMS:
是一種以獲得最短回收停頓時間為目標(biāo)的收集器,標(biāo)記清除算法,運作過程:初始標(biāo)記,并發(fā)標(biāo)記,重新標(biāo)記,并發(fā)清除,收集結(jié)束會產(chǎn)生大量空間碎片;
G1:
標(biāo)記整理算法實現(xiàn),運作流程主要包括以下:初始標(biāo)記,并發(fā)標(biāo)記,最終標(biāo)記,篩選回收。不會產(chǎn)生空間碎片,可以精確地控制停頓;
G1將整個堆分為大小相等的多個Region(區(qū)域),G1跟蹤每個區(qū)域的垃圾大小,在后臺維護(hù)一個優(yōu)先級列表,每次根據(jù)允許的收集時間,優(yōu)先回收價值最大的區(qū)域,已達(dá)到在有限時間內(nèi)獲取盡可能高的回收效率;
七、什么是類加載?
虛擬機把描述類的數(shù)據(jù)加載到內(nèi)存里面,并對數(shù)據(jù)進(jìn)行校驗、解析和初始化,最終變成可以被虛擬機直接使用的class對象;
八、類加載的過程?
主要分為以下幾個過程:加載、驗證、準(zhǔn)備、解析、初始化;
加載:
加載分為三步:
1、通過類的全限定性類名獲取該類的二進(jìn)制流;
2、將該二進(jìn)制流的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu);
3、在堆中為該類生成一個class對象;
驗證:
驗證該class文件中的字節(jié)流信息復(fù)合虛擬機的要求,不會威脅到j(luò)vm的安全;
準(zhǔn)備:
為class對象的靜態(tài)變量分配內(nèi)存,初始化其初始值;
解析:
該階段主要完成符號引用轉(zhuǎn)化成直接引用;
初始化:
到了初始化階段,才開始執(zhí)行類中定義的java代碼;
初始化階段是調(diào)用類構(gòu)造器的過程;
九、什么是類加載器,常見的類加載器有哪些?
類加載器是指:通過一個類的全限定性類名獲取該類的二進(jìn)制字節(jié)流叫做類加載器;
類加載器分為以下四種:
啟動類加載器:
用來加載java核心類庫,無法被java程序直接引用;
擴展類加載器:
用來加載java的擴展庫,java的虛擬機實現(xiàn)會提供一個擴展庫目錄,該類加載器在擴展庫目錄里面查找并加載java類;
系統(tǒng)類加載器:
它根據(jù)java的類路徑來加載類,一般來說,java應(yīng)用的類都是通過它來加載的;
自定義類加載器:
由java語言實現(xiàn),繼承自ClassLoader;
十、什么是雙親委派模型?
當(dāng)一個類加載器收到一個類加載的請求,他首先不會嘗試自己去加載,而是將這個請求委派給父類加載器去加載,只有父類加載器在自己的搜索范圍類查找不到給類時,子加載器才會嘗試自己去加載該類;
十一、為什么需要雙親委派模型?
為了防止內(nèi)存中出現(xiàn)多個相同的字節(jié)碼;
因為如果沒有雙親委派的話,用戶就可以自己定義一個java.lang.String類,那么就無法保證類的唯一性;
十二、怎么打破雙親委派模型?
自定義類加載器,繼承ClassLoader類,重寫loadClass方法和findClass方法;
十三、強引用、軟應(yīng)用、弱引用、虛引用的區(qū)別?
強引用:強引用是我們使用最廣泛的引用,如果一個對象具有強引用,那么垃圾回收期絕對不會回收它,當(dāng)內(nèi)存空間不足時,垃圾回收器寧愿拋出OutOfMemoryError,也不會回收具有強引用的對象;我們可以通過顯示的將強引用對象置為null,讓gc認(rèn)為該對象不存在引用,從而來回收它;
軟引用:軟應(yīng)用是用來描述一些有用但不是必須的對象,在java中用SoftReference來表示,當(dāng)一個對象只有軟應(yīng)用時,只有當(dāng)內(nèi)存不足時,才會回收它;
軟引用可以和引用隊列聯(lián)合使用,如果軟引用所引用的對象被垃圾回收器所回收了,虛擬機會把這個軟引用加入到與之對應(yīng)的引用隊列中;
弱引用:弱引用是用來描述一些可有可無的對象,在java中用WeakReference來表示,在垃圾回收時,一旦發(fā)現(xiàn)一個對象只具有軟引用的時候,無論當(dāng)前內(nèi)存空間是否充足,都會回收掉該對象;
弱引用可以和引用隊列聯(lián)合使用,如果弱引用所引用的對象被垃圾回收了,虛擬機會將該對象的引用加入到與之關(guān)聯(lián)的引用隊列中;
虛引用:虛引用就是一種可有可無的引用,無法用來表示對象的生命周期,任何時候都可能被回收,虛引用主要使用來跟蹤對象被垃圾回收的活動,虛引用和軟引用與弱引用的區(qū)別在于:虛引用必須和引用隊列聯(lián)合使用;在進(jìn)行垃圾回收的時候,如果發(fā)現(xiàn)一個對象只有虛引用,那么就會將這個對象的引用加入到與之關(guān)聯(lián)的引用隊列中,程序可以通過發(fā)現(xiàn)一個引用隊列中是否已經(jīng)加入了虛引用,來了解被引用的對象是否需要被進(jìn)行垃圾回收;
到此這篇關(guān)于2020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案(史上最全)的文章就介紹到這了,更多相關(guān)JVM面試題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!文章的最后祝大家在工作的工作順利,在找工作的都能拿到自己滿意的offer!
相關(guān)文章
- 這篇文章主要介紹了10道JVM常見面試題解析(附答案),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)2020-09-04
- 這篇文章主要介紹了JVM相關(guān)面試題及答案(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-09-02
- 這篇文章主要介紹了2020年JVM高頻率面試題整理,真是小編下了血本給大家整理出來的,值得大家收藏,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-09
- 這篇文章主要介紹了JVM面試題小結(jié)(2020最新版),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-02-21
- 這篇文章主要介紹了2019年JVM面試都問了什么?(附答案解析),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-12-04
Java研發(fā)面試99題(含答案):JVM+Spring+MySQL+線程池+鎖
這篇文章主要介紹了Java研發(fā)面試99題,主要包括了JVM,Spring,MySQL,線程池,鎖等,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-07-16- JVM(Java 虛擬機)算是面試必問的問題的了,而但凡問 JVM 一定會問的第一個問題就是:講一講 JVM 的組成?那本文就注重講一下 JVM 的組成,感興趣的可以了解一下2019-04-10
- 這篇文章主要介紹了30道有趣的JVM面試題(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-11-26