面試必問的JVM應該怎麼學(面試題含答案)

java虛擬機的基本結構如圖:
在這裏插入圖片描述
1)類加載子系統負責從文件系統或者網絡中加載Class信息,加載的類信息存放於一塊稱爲方法區的內存空間。除了類的信息外,方法區中可能還會存放運行時常量池信息,包括字符串字面量和數字常量(這部分常量信息是Class文件中常量池部分的內存映射)。

2)java堆在虛擬機啓動的時候建立,它是java程序最主要的內存工作區域。幾乎所有的java對象實例都存放在java堆中。堆空間是所有線程共享的,這是一塊與java應用密切相關的內存空間。

3)java的NIO庫允許java程序使用直接內存。直接內存是在java堆外的、直接向系統申請的內存空間。通常訪問直接內存的速度會優於java堆。因此出於性能的考慮,讀寫頻繁的場合可能會考慮使用直接內存。由於直接內存在java堆外,因此它的大小不會直接受限於Xmx指定的最大堆大小,但是系統內存是有限的,java堆和直接內存的總和依然受限於操作系統能給出的最大內存。

4)垃圾回收系統是java虛擬機的重要組成部分,垃圾回收器可以對方法區、java堆和直接內存進行回收。其中,java堆是垃圾收集器的工作重點。和C/C++不同,java中所有的對象空間釋放都是隱式的,也就是說,java中沒有類似free()或者delete()這樣的函數釋放指定的內存區域。對於不再使用的垃圾對象,垃圾回收系統會在後臺默默工作,默默查找、標識並釋放垃圾對象,完成包括java堆、方法區和直接內存中的全自動化管理。

5)每一個java虛擬機線程都有一個私有的java棧,一個線程的java棧在線程創建的時候被創建,java棧中保存着幀信息,java棧中保存着局部變量、方法參數,同時和java方法的調用、返回密切相關。

6)本地方法棧和java棧非常類似,最大的不同在於java棧用於方法的調用,而本地方法棧則用於本地方法的調用,作爲對java虛擬機的重要擴展,java虛擬機允許java直接調用本地方法(通常使用C編寫)

7)PC(Program Counter)寄存器也是每一個線程私有的空間,java虛擬機會爲每一個java線程創建PC寄存器。在任意時刻,一個java線程總是在執行一個方法,這個正在被執行的方法稱爲當前方法。如果當前方法不是本地方法,PC寄存器就會指向當前正在被執行的指令。如果當前方法是本地方法,那麼PC寄存器的值就是undefined

8)執行引擎是java虛擬機的最核心組件之一,它負責執行虛擬機的字節碼,現代虛擬機爲了提高執行效率,會使用即時編譯技術將方法編譯成機器碼後再執行。

JVM面試問題

1、內存模型以及分區,需要詳細到每個區放什麼。

JVM 分爲堆區和棧區,還有方法區,初始化的對象放在堆裏面,引用放在棧裏面,class類信息常量池(static常量和static變量)等放在方法區

new:

方法區:主要是存儲類信息,常量池(static常量和static變量),編譯後的代碼(字節碼)等數據

堆:初始化的對象,成員變量 (那種非static的變量),所有的對象實例和數組都要在堆上分配

棧:棧的結構是棧幀組成的,調用一個方法就壓入一幀,幀上面存儲局部變量表,操作數棧,方法出口等信息,局部變量表存放的是8大基礎類型加上一個應用類型,所以還是一個指向地址的指針

本地方法棧:主要爲Native方法服務

程序計數器:記錄當前線程執行的行號

2、堆裏面的分區:Eden,survival (from+ to),老年代,各自的特點。

堆裏面分爲新生代和老生代(java8取消了永久代,採用了Metaspace),新生代包含Eden+Survivor區,survivor區裏面分爲from和to區,內存回收時,如果用的是複製算法,從from複製到to,當經過一次或者多次GC之後,存活下來的對象會被移動到老年區,當JVM內存不夠用的時候,會觸發Full GC,清理JVM老年區

當新生區滿了之後會觸發YGC,先把存活的對象放到其中一個Survice

區,然後進行垃圾清理。因爲如果僅僅清理需要刪除的對象,這樣會導致內存碎

片,因此一般會把Eden 進行完全的清理,然後整理內存。那麼下次GC 的時候,

就會使用下一個Survive,這樣循環使用。如果有特別大的對象,新生代放不下,

就會使用老年代的擔保,直接放到老年代裏面。因爲JVM 認爲,一般大對象的存

活時間一般比較久遠。

3、對象創建方法,對象的內存分配,對象的訪問定位。

new 一個對象

4、GC的兩種判定方法:

引用計數法:指的是如果某個地方引用了這個對象就+1,如果失效了就-1,當爲0就會回收但是JVM沒有用這種方式,因爲無法判定相互循環引用(A引用B,B引用A)的情況

引用鏈法: 通過一種GC ROOT的對象(方法區中靜態變量引用的對象等-static變量)來判斷,如果有一條鏈能夠到達GC ROOT就說明,不能到達GC ROOT就說明可以回收

5、SafePoint是什麼

比如GC的時候必須要等到 Java 線程都進入到safepoint的時候VMThread才能開始執行GC,

循環的末尾 (防止大循環的時候一直不進入safepoint,而其他線程在等待它進入safepoint)

方法返回前

調用方法的call之後

拋出異常的位置

6、GC的三種收集方法:標記清除、標記整理、複製算法的原理與特點,分別用在什麼地方,如果讓你優化收集方法,有什麼思路?

先標記,標記完畢之後再清除,效率不高,會產生碎片

複製算法:分爲8:1的Eden區和survivor區,就是上面談到的YGC

標記整理:標記完畢之後,讓所有存活的對象向一端移動

7、GC收集器有哪些?CMS收集器與G1收集器的特點。

並行收集器:串行收集器使用一個單獨的線程進行收集,GC時服務有停頓時間

串行收集器:次要回收中使用多線程來執行

CMS收集器是基於 “標記—清除” 算法實現的,經過多次標記纔會被清除

G1從 整體來看是基於“標記—整理” 算法實現的收集器,從 局部(兩個Region之間)上來看是基於“複製” 算法實現的

8、Minor GC與Full GC分別在什麼時候發生?

新生代內存不夠用時候發生MGC也叫YGC,JVM內存不夠的時候發生FGC

9、幾種常用的內存調試工具:jmap、jstack、jconsole、jhat

jstack可以看當前棧的情況,jmap查看內存,jhat 進行dump堆的信息

mat(eclipse的也要了解一下)

10、類加載的幾個過程:

加載、驗證、準備、解析、初始化。然後是使用和卸載了

通過全限定名來加載生成class對象到內存中,然後進行驗證這個class文件,包括文件格式校驗、元數據驗證,字節碼校驗等。準備是對這個對象分配內存。解析是將符號引用轉化爲直接引用(指針引用),初始化就是開始執行構造器的代碼

11、雙親委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。

Bootstrap ClassLoader:啓動類加載器,負責將$ Java_Home/lib下面的類庫加載到內存中(比如rt.jar

Extension ClassLoader:標準擴展(Extension)類加載器,它負責將$Java_Home /lib/ext或者由系統變量 java.ext.dir指定位置中的類庫加載到內存中。

ApplicationClassLoader:它負責將系統類路徑(CLASSPATH)中指定的類庫加載到內存中。開發者可以直接使用系統類加載器

雙親委派模型是某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次遞歸,如果父類加載器可以完成類加載任務,就成功返回;只有父類加載器無法完成此加載任務時,才自己去加載。-----例如類java.lang.Object,它存在在rt.jar中,無論哪一個類加載器要加載這個類,最終都是委派給處於模型最頂端的Bootstrap ClassLoader進行加載,因此Object類在程序的各種類加載器環境中都是同一個類。相反,如果沒有雙親委派模型而是由各個類加載器自行加載的話,如果用戶編寫了一個java.lang.Object的同名類並放在ClassPath中,那系統中將會出現多個不同的Object類,程序將混亂

覺得不錯請點贊支持,歡迎留言或進我的個人羣855801563領取【架構資料專題目合集90期】、【BATJTMD大廠JAVA面試真題1000+】,本羣專用於學習交流技術、分享面試機會,拒絕廣告,我也會在羣內不定期答題、探討

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章