面試必問的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之間)上來看是基於“複製” 演算法實現的
[GC收集器]: http://www.jianshu.com/p/50d5c88b272d
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類,程式將混亂
面試資料及學習資料

需要面試題彙總(可私信我免費領取答案)私信【面試資料】即可領取
附加java開發的資料(面試資源與經驗總結,Dubbo、Redis、設計模式、Netty、zookeeper、Spring cloud、分散式、高併發等架構技術視訊教程資料,架構思維導圖,以及面試資料,瞭解最新的學習動態;瞭解最新的阿里、京東招聘資訊)