JVM 知識點彙總(問題)
JVM 知識點有 6 個大方向,其中,內存模型、類加載機制、GC 垃圾回收是比較重點的內容。性能調優部分偏重實際應用,重點突出實踐能力。編譯器優化和執行模式部分偏重理論基礎,主要掌握知識點。
各個部分需要了解的知識點如下。
-
內存模型:程序計數器、方法區、堆、棧、本地方法棧的作用,保存哪些數據。
-
類加載:雙親委派的加載機制,以及常用類加載器分別加載哪種類型的類。
-
GC:分代回收的思想和依據,以及不同垃圾回收算法實現的思路、適合的場景。
-
性能調優:常用的 JVM 優化參數的作用,參數調優的依據,常用的 JVM 分析工具能分析哪類問題,以及使用方法。
-
執行模式:解釋、編譯、混合模式的優缺點,Java7 提供的分層編譯技術。需要知道 JIT 即時編譯技術和 OSR(棧上替換),知道 C1、C2 編譯器針對的場景,其中 C2 針對 Server 模式,優化更激進。在新技術方面可以瞭解 Java10 提供的由 Java 實現的 Graal 編譯器。
-
編譯優化:前端編譯器 javac 的編譯過程、AST 抽象語法樹、編譯期優化和運行期優化。編譯優化的常用技術包括公共子表達式的消除、方法內聯、逃逸分析、棧上分配、同步消除等。明白了這些才能寫出對編譯器友好的代碼。
JVM 的內容相對來說比較集中,但是對知識深度的掌握要求較高。
內存模型(看這裏)
- 運行時數據區: 程序計數器、棧、本地方法棧、方法區、堆
- Java內存模型JMM
- HotSpot虛擬機對象
說明:主要了解他們分別保存了哪些數據,以及有什麼作用
類加載機制(看這裏)
- 類加載的基本流程
- 雙親委派機制
- 啓動類加載器Bootstrap ClassLoader
- 擴展類加載器 Extension ClassLoader
- 應用程序類加載器 Application ClassLoader
- 自定義類加載器
- 破壞雙親委派模型:JDBC、熱部署都是指定類加載器加載。
說明:瞭解雙親委派機制,以及常見的類加載器分別加載哪種類型的類和他們的執行順序
GC(看這裏)
- GC算法及其各自的優缺點:標記-清除、複製、標記-整理、分代收集
- 分代回收
年輕代、老年代 - 收集器分類:串行收集器、並行收集器、併發收集器
- 垃圾收集器
年輕代:Serial、ParNew、Parallel Scavenge
老年代:Serial Old、Parallel Old、CMS
年輕代和老年代:G1
說明:分代回收的思想和依據,以及不同GC算法實現的思路和適合的場景
性能調優
- JVM參數看這裏
- 調優的參數主要分爲下面幾個方向考慮:
1. 內存管理配置,如:新生代老年代永久代的大小、新生代老年代的比例、新生代各個區域所佔比例、新生代對象晉升老年代的年齡閾值
2. 垃圾收集器配置,如:新生代和老年代分別採用的收集器類型,各個收集器的運行參數配置、並行收集器並行的線程數
3. 多線程相關配置:使用自旋鎖時默認的自旋次數,是否使用偏向鎖等
4. 調試參數配置:內存溢出時是否生成快照、打印JUC中鎖狀態、打印GC詳細信息等等。
具體配置參數可以通過查看Hotspot的參數表。
可以簡單的將調優細分爲下面幾個點:
1. 設置堆的最大和最小值
2. 新生代老年代永久代的大小、新生代老年代的比例、新生代各個區域所佔比例、新生代對象晉升老年代的年齡閾值
3. 查看峯值的老年代的大小,在不影響Full GC的情況下可以加大年輕代,減少Minor GC
3. 配置好的機器可以採用併發收集器
4. 每個線程默認開啓1M堆棧存放棧幀,可以根據情況調小
關於OOM問題和CPU佔用過高問題,都可以通過JVisualVM來觀察各個線程CPU佔用和內存佔用
說明:常用的JVM優化參數的作用,參數調優的依據,常用的JVM分析工具能分析哪一類問題以及使用方法。
-Xms1024M 初始堆內存空間
-Xmx1024M 最大堆內存空間
-XX:NewRatio=4 設置年輕的和老年代的內存比例爲 1:4
-XX:SurvivorRatio=3 設置新生代 From Survivor或To Survivor 與Eden 比例爲 1:3,即:Eden區佔新生代的3/(3+1+1)
-XX:PermSize=128M JDK1.8後用-XX:MetaspaceSize代替
-XX:MaxPermSize=246M JDK1.8後用-XX:MaxMetaspaceSize代替
-XX:+PrintGC:開啓打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 詳細信息
還可以指定新生代和老年代的垃圾收集器
JVM調優主要是配置:堆大小、各分代的大小、指定各分代串行和並行的收集器、指定收集器的相關參數、配置打印GC回收的過程日誌信息
編譯優化(瞭解)
- 指令重排
- 內聯
- 逃逸分析:方法逃逸、線程逃逸
說明:編譯優化包括javac編譯過程、AST抽象語法樹、編譯期優化和運行期優化。常用的技術包括公共子表達式的消除、方法內聯、逃逸分析、同步消除等。
常見問題排查
- 內存泄露
方式一:JDK工具:jvisualvm的profiler分析器插件可以直接進行內存分析。
方式二:JDK工具:jvisualvm可以到處內存快照dump文件,然後使用idea插件jprofiler分析dump文件
方式三:先使用jps命令查看Java進程pid,然後使用jmap命令導出內存快照dump文件,然後使用idea插件jprofiler分析dump文件。還可以使用jstat命令查看GC情況 - 死鎖
方式一:JDK工具:jconsole的線程監控提供了檢測死鎖的功能
方式二:先試用jps查看Java進程的pid,在使用jstack命令查看對應進程的線程情況。 - CPU佔用過高
方式一:JDK工具:jvisualvm工具的profiler分析器插件可以直接分析線程的CPU佔用情況。
方式二:先試用linux的top命令查看對應占用CPU高的進程,然後在利用linux的ps命令查看對應的進程的線程大致情況,在利用jstack命令查看具體有問題線程的堆棧情況。
考察點
總結 JVM 相關的面試考察點如下:
-
深入瞭解 JVM 的內存模型和 Java 的內存模型;
-
要了解類的加載過程,瞭解雙親委派機制;
-
要理解內存的可見性與 Java 內存模型對原子性、可見性、有序性的保證機制;
-
要了解常用的 GC 算法的特點、執行過程,和適用場景,例如 G1 適合對最大延遲有要求的場合,ZGC 適用於 64 位系統的大內存服務中;
-
要了解常用的 JVM 參數,明白對不同參數的調整會有怎樣的影響,適用什麼樣的場景,例如垃圾回收的併發數、偏向鎖設置等。
加分項
如果想要給面試官留下更好的印象,注意這些加分項。
-
如果在編譯器優化方面有深入的瞭解的話,會讓面試官覺得你對技術的深度比較有追求。例如知道在編程時如何合理利用棧上分配降低 GC 壓力、如何編寫適合內聯優化等代碼等。
-
如果你能有線上實際問題的排查經驗或思路那就更好了,面試官都喜歡動手能力強的同學。例如解決過線上經常 FullGC 問題,排查過內存泄露問題等。
-
如果能有針對特定場景的 JVM 優化實踐或者優化思路,也會有意想不到的效果。例如針對高併發低延遲的場景,如何調整 GC 參數儘量降低 GC 停頓時間,針對隊列處理機如何儘可能提高吞吐率等;
-
如果對最新的 JVM 技術趨勢有所瞭解,也會給面試官留下比較深刻的印象。例如瞭解 ZGC 高效的實現原理,瞭解 Graalvm 的特點等。
關於JVM常見的問題
-
簡單描述一下JVM內存模型,回答這個問題時記得和麪試官確認是希望回答 JVM 的內存模型,還是 Java 對內存訪問的模型,不要答跑偏。
-
什麼情況下會觸發MinGC、MajorGC、FullGC?
Minor GC 用於清理年輕代,Eden滿了,就觸發Minor GC ,清理無用對象,把有用對象放到Survivor1或Survivor2中。Major GC 用於清理老年代。
Full GC 清理年輕代、老年代區域,成本高,對系統性能產生影響 -
雙親委派機制的加載流程是怎樣的,有什麼好處?能否說出一些破壞雙親委派機制的情況?
-
JDK1.8爲什麼用Metaspace替換的PermGen?Metaspace保存在哪裏
-
編譯期會對指令做哪些優化?簡單描述編譯期的指令重排
-
簡單描述一下volatile可以解決什麼問題?如何做到的? volatile 要重點回答強制主內存讀寫同步以及防止指令重排序兩點。
-
簡單描述一下GC的分代回收。
-
G1垃圾回收算法與CMS的區別有哪些?
-
對象的引用有哪幾種?強、軟、弱、虛,這幾種引用有什麼特點?答出分別在 GC 中的處理方式。
-
用過哪些JVM調試工具,他們分別用來分析什麼內容?
jvisualvm 內存佔用信息、CPU佔用信息。
jconsole可以查看內存情,也可以查看活躍的線程情況。
線程分析工具 jstack 和獲取堆信息的 jmap 等。