Java語言區(qū)別于其他計算機語言的最大特點就是面向?qū)ο笮?,也被稱為與平臺無關(guān)的編程語言,java能實現(xiàn)這樣的特點,就是因為JVM虛擬機的作用,因此關(guān)于JVM的知識點都是需要大家掌握的。下面整理了10道JVM面試題,是在java面試中考察幾率最大的題目,一起來學習吧。
1.什么情況下會發(fā)生棧內(nèi)存溢出?
- 棧是線程私有的,他的生命周期與線程相同,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀,用來存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。局部變量表又包含基本數(shù)據(jù)類型,對象引用類型;
- 如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError異常,方法遞歸調(diào)用產(chǎn)生這種結(jié)果;
- 如果Java虛擬機棧可以動態(tài)擴展,并且擴展的動作已經(jīng)嘗試過,但是無法申請到足夠的內(nèi)存去完成擴展,或者在新建立線程的時候沒有足夠的內(nèi)存去創(chuàng)建對應(yīng)的虛擬機棧,那么Java虛擬機將拋出一個OutOfMemory異常;
- 參數(shù)-Xss 去調(diào)整JVM棧的大小。
2、介紹JVM內(nèi)存模型
JVM內(nèi)存結(jié)構(gòu)如下:

- 程序計數(shù)器:當前線程所執(zhí)行的字節(jié)碼的行號指示器,用于記錄正在執(zhí)行的虛擬機字節(jié)指令地址,線程私有。
- Java虛擬棧:存放基本數(shù)據(jù)類型、對象的引用、方法出口等,線程私有。
- Native方法棧:和虛擬棧相似,只不過它服務(wù)于Native方法,線程私有。
- Java堆:java內(nèi)存最大的一塊,所有對象實例、數(shù)組都存放在java堆,GC回收的地方,線程共享。
- 方法區(qū):存放已被加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼數(shù)據(jù)等。(即永久帶),回收目標主要是常量池的回收和類型的卸載,各線程共享。
3.JVM內(nèi)存新生代中為什么要分為Eden和Survivor?
- 如果沒有Survivor,Eden區(qū)每進行一次Minor GC,存活的對象就會被送到老年代。老年代很快被填滿,觸發(fā)Major GC.老年代的內(nèi)存空間遠大于新生代,進行一次Full GC消耗的時間比Minor GC長得多,所以需要分為Eden和Survivor;
- Survivor的存在意義,就是減少被送到老年代的對象,進而減少Full GC的發(fā)生,Survivor的預(yù)篩選保證,只有經(jīng)歷16次Minor GC還能在新生代中存活的對象,才會被送到老年代;
- 設(shè)置兩個Survivor區(qū)最大的好處就是解決了碎片化,剛剛新建的對象在Eden中,經(jīng)歷一次Minor GC,Eden中的存活對象就會被移動到第一塊survivor space S0,Eden被清空;等Eden區(qū)再滿了,就再觸發(fā)一次Minor GC,Eden和S0中的存活對象又會被復(fù)制送入第二塊survivor space S1(這個過程非常重要,因為這種復(fù)制算法保證了S1中來自S0和Eden兩部分的存活對象占用連續(xù)的內(nèi)存空間,避免了碎片化的發(fā)生)。
4.JVM的永久代中會發(fā)生垃圾回收嗎?
垃圾回收不會發(fā)生在永久代,如果永久代滿了或者是超過了臨界值,會觸發(fā)完全垃圾回收(Full GC)。如果你仔細查看垃圾收集器的輸出信息,就會發(fā)現(xiàn)永久代也是被回收的。這就是為什么正確的永久代大小對避免Full GC是非常重要的原因。請參考下Java8:從永久代到元數(shù)據(jù)區(qū) (注:Java8中已經(jīng)移除了永久代,新加了一個叫做元數(shù)據(jù)區(qū)的native內(nèi)存區(qū))。
5.什么是類加載器,類加載器有哪些?
實現(xiàn)通過類的權(quán)限定名獲取該類的二進制字節(jié)流的代碼塊叫做類加載器。主要有以下四種類加載器:
- 啟動類加載器(Bootstrap ClassLoader)用來加載java核心類庫,無法被java程序直接引用;
- 擴展類加載器(extensions class loader):它用來加載java的擴展庫。Java 虛擬機的實現(xiàn)會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載java類;
- 系統(tǒng)類加載器(system class loader):它根據(jù)java應(yīng)用的類路徑(CLASSPATH)來加載Java類。一般來說,Java 應(yīng)用的類都是由它來完成加載的??梢酝ㄟ^ClassLoader.getSystemClassLoader()來獲取它;
- 用戶自定義類加載器,通過繼承 java.lang.ClassLoader類的方式實現(xiàn)。
6.簡述java類加載機制?
虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗,解析和初始化,最終形成可以被虛擬機直接使用的java類型。
7.類加載器雙親委派模型機制?
當一個類收到了類加載請求時,不會自己先去加載這個類,而是將其委派給父類,由父類去加載,如果此時父類不能加載,反饋給子類,由子類去完成類的加載。
8.Java對象創(chuàng)建過程?
- JVM遇到一條新建對象的指令時首先去檢查這個指令的參數(shù)是否能在常量池中定義到一個類的符號引用,然后加載這個類;
- 為對象分配內(nèi)存。一種辦法“指針碰撞”、一種辦法“空閑列表”,最終常用的辦法“本地線程緩沖分配(TLAB)”;
- 將除對象頭外的對象內(nèi)存空間初始化為0;
- 對對象頭進行必要設(shè)置。
9.對象分配的規(guī)則?
- 對象優(yōu)先分配在Eden區(qū),如果Eden區(qū)沒有足夠的空間時,虛擬機執(zhí)行一次Minor GC;
- 大對象直接進入老年代(大對象是指需要大量連續(xù)內(nèi)存空間的對象)。這樣做的目的是避免在Eden區(qū)和兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存拷貝(新生代采用復(fù)制算法收集內(nèi)存);
- 長期存活的對象進入老年代。虛擬機為每個對象定義了一個年齡計數(shù)器,如果對象經(jīng)過了1次Minor GC那么對象會進入Survivor區(qū),之后每經(jīng)過一次Minor GC那么對象的年齡加1,直到達到閥值對象進入老年區(qū)。
- 動態(tài)判斷對象的年齡。如果Survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入老年代。
- 空間分配擔保。每次進行Minor GC時,JVM會計算Survivor區(qū)移至老年區(qū)的對象的平均大小,如果這個值大于老年區(qū)的剩余值大小則進行一次Full GC,如果小于檢查HandlePromotionFailure設(shè)置,如果true則只進行Monitor GC,如果false則進行Full GC。
10.描述一下JVM加載class文件的原理機制?
JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現(xiàn)的,Java中的類加載器是一個重要的Java運行時系統(tǒng)組件,它負責在運行時查找和裝入類文件中的類。由于Java的跨平臺性,經(jīng)過編譯的Java源程序并不是一個可執(zhí)行程序,而是一個或多個類文件。當Java程序需要使用某個類時,JVM會確保這個類已經(jīng)被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個字節(jié)數(shù)組讀入.class文件,然后產(chǎn)生與所加載類對應(yīng)的Class對象。加載完成后,Class對象還不完整,所以此時的類還不可用。當類被加載后就進入連接階段,這一階段包括驗證、準備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟。最后JVM對類進行初始化,包括:1)如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類;2)如果類中存在初始化語句,就依次執(zhí)行這些初始化語句。 類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載。
JVM使java成為應(yīng)用程序可以運行在任意的平臺變成可能,不需要程序員為每一個平臺單獨重寫或者是重新編譯。所以需要大家對JVM的內(nèi)容熟練掌握,上面的JVM面試題是學習虛擬機的基礎(chǔ)知識,也是在java面試中??嫉降念}目,希望朋友們可以好好學習JVM的相關(guān)知識,同時也可以更多的學習和關(guān)注java面試題,這樣才能在眾多面視者中脫穎而出。