JVM的一些相關問題

內容都是攢的,不喜勿噴!

常見問題

1. JVM 年輕代到年老代晉升過程?
  • 對象在Form和To之間來回複製,年齡達到15(默認值,可通過 MaxTenuringThreshold 修改),晉升老年代

  • 分配對象超過eden內存的一半,直接進入老年代。小於eden一半但沒有內存空間,進行minor GC,survivor也放不下,進入老年代

  • 動態年齡判斷,某個年齡對象超過survivor空間的一半,大於等於某個年齡的對象直接進入老年代

2. Minor GC,Major GC和Full GC區別?
  • Minor GC:年輕代GC
  • Major GC:年老代GC
  • Full GC:整個堆空間GC(年輕代和年老代)
3. 發生 Full GC 的幾種情況?
  • System.gc() 方法顯示調用(只是建議進行GC)
  • 老年代空間不足:只有在新生代對象轉入大對象(數組等)分配時,老年代纔會出現內存不足情況,若 Full GC後空間依舊不足,拋出內存溢出異常
  • CMS GC時出現 promotion failedconcurrent mode failure
    • promotion failed:發生Minor GC時,survivor space放不下了,只能晉升老年代,老年代也放不下
    • concurrent mode failure:執行CMS GC的同時有對象要放入老年代,而此時老年代空間不足造成的(有時候“空間不足”是CMS GC時當前的浮動垃圾過多導致暫時性的空間不足觸發Full GC)
  • 統計的到的Minor GC晉升老年代對象平均大小大於老年代剩餘空間
    • Hotspot爲避免晉升失敗,會統計之前每次Minor GC後晉升對象的平均大小是否可以被老年代容納,不能的話會觸發Full GC
    • 例如第一次Minor GC後有6M晉升到老年代,那麼下次Minor GC發生時就會檢查老年代是否有6M大小的空間
    • 新生代使用PS GC(併發GC收集器)時,PS GC只對當前負責,檢查本次要晉升的對象大小能否被老年代容納,不能的話出觸發Full GC
  • 堆中分配很大的對象:特指需要大量連續空間的對象
  • 調用了 jmap -histo:live [pid]:立即出發Full GC
4. 如何拿到 JVM 的 dump 文件?
  • jstack [pid] > xxx.txt:打印堆棧信息到文件
  • jstack -l [pid] > xxx.txt:打印堆棧信息(包含鎖)到文件
  • kill -3
  • 添加 JVM 參數:-XX:+HEAPDUMPONOUTOFMEMORYERROR(在內存溢出是保存堆棧信息),一般配合 -XX:HeapDumpPath=PATH 使用(可用 jinfo 命令運行時修改
  • jmap -dump:format=b,file=xxx.dump [pid]
5. JVM 出現 fullGC 很頻繁,怎麼去線上排查問題?
  • jstat 查看GC信息觀察GC後的堆空間大小並判斷是否空間不足導致
    • 空間不足導致:拿到 dump 文件,放入 JVisualVM 觀察原因
    • 空間充足:觀察程序中有沒顯示調用 System.gc() 方法
6. 對象如何進行訪問定位?
  • 句柄:在堆空間中開闢一塊空間用來存放句柄池,句柄池存放對象的類型指針和對象的實例指針,reference指針指向句柄

    • 好處:reference指向穩定的句柄,當堆空間進行gc時,對象的移動只會改變句柄中的對象實例指針,對reference沒有影響
  • 直接指針:堆中實例對象存放實例類型,reference指針直接指向實例對象

    • 好處:速度更快,節省一次指針定位的開銷

7. 對象創建過程?
8. GC對象的判定方法?
  • 引用計數法:爲對象添加計數器,有引用該對象的地方時,計數器+1
    • 優點:效率高,簡單
    • 缺點:存在循環引用問題
  • 可達性分析算法:通過一系列GcRoots的對象爲起點向下搜索,走過的路徑爲引用鏈,沒在引用鏈上爲廢棄對象
    • 可做爲GCRoot的對象(jdk1.7):
      • 虛擬機棧引用的對象
      • 方法區中類靜態屬性引用的變量(static對象)
      • 方法區中常量引用的對象(final對象)
      • 本地方法棧中Native方法引用的變量
9. 四種引用?
  • 強引用:new對象就是強引用,JVM拋出OOM也不會清除
  • 軟引用:JVM內存不足時會回收軟引用對象
  • 弱引用:JVM只要進行GC就會回收弱引用對象
  • 虛引用:幽靈引用,虛引用不會對對象生命週期產生印象,也無法通過虛引用獲取對象
10. 垃圾回收算法?
  • 標記清除:先標記再清除,有效率問題且會產生大量不連續的內存碎片
  • 標記整理:先標記,將標記數據移到內存一端,清除其餘部分,有效率問題但不會產生內存碎片
  • 複製算法:將內存一份爲二,使用一半內存,當垃圾回收時將存活對象放入另一半,然後清理自己的內存。好處是效率高且沒有內存碎片,但會犧牲一半內存。在jvm中年輕代使用複製算法,但年輕代對象都是朝生夕死,所以內存分配時eden佔用80%,而survivor佔用%20來使用
  • 分代算法:新生代複製算法,老年代標記整理或標記清除
11. 垃圾收集器?
  • Serial收集器:年輕代串行收集器,當GC收集時,工作線程必須暫停(stop the world)直至收集結束,使用複製算法
  • Serial Old收集器:年老代串行收集器,特性和Serial一樣,使用標記整理算法
  • Parallel Scavenge收集器:年輕代並行收集器,吞吐量優先收集器,使用複製算法
  • Parallel Old收集器:年老代並行收集器,使用標記整理算法
  • ParNew收集器:年輕代並行收集器,Serial收集器的多線程版本,爲了配合CMS而生,複製算法
  • CMS收集器:年老代併發收集器,目標是最短停頓回收時間,注重用戶體驗,標記清除算法
  • 運行過程:
    • 初始標記(Stop-The-World):僅標記GCRoot能關聯到的對象
      • 併發標記:標記GCRoot關聯的所有不相關對象(從併發就可以看出,他是和用戶線程一起工作的)
      • 重新標記(Stop-The-World):對併發標記期間因用戶操作而導致標記變動的對象進行重新標記
      • 併發清除:進行清除
    • 優點:最短停頓回收時間,注重用戶體驗
    • 缺點:
      • CPU資源敏感
      • 無法處理浮動垃圾,浮動垃圾過多時會啓用Serial Old收集器
      • 大量內存碎片,再次分配大對象分配不下時,會引發一次FullGC,通過-XX:+UseCMSCompactAtFullCollection,在要進行FullGC時,進行內存整理(無法併發,慢)
  • G1收集器:
12. 理解GC日誌?
13. JVM常用參數?

Oracle的官方文檔

14. 分配擔保機制?

在發生Minor GC前,JVM檢查新生代總大小是否可被老年代最大連續空間容納,可容納時進行Minor GC,否則檢查是否允許分配擔保失敗,如果允許,判斷老年代最大連續空間是否大於以往晉升對象的平均大小,若大於,進行Minor GC(有風險,可能這次超出平均大小,老年代接不住)。若小於或不允許分配擔保失敗,則轉爲執行Full GC

15. 類加載機制?
  • 加載

    1. 通過全類名獲取類的二進制字節流

    2. 將字節流所代表的的靜態存儲結構轉換爲方法區(元空間)的運行時數據結構

    3. 在內存中生成代表該類的Class文件,作爲方法區(元空間)這些數據的訪問入口

  • 驗證

    1. 文件格式驗證
    2. 元數據驗證
    3. 字節碼驗證
    4. 符號引用驗證
  • 準備:正式爲類變量分配內存並設置類變量初始值(就是默認值),例如public static int val = 111;,這裏分配的是初值0;

  • 解析將虛擬機常量池內的符號引用替換爲直接引用的過程,主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用限定符7種符號引用進行

  • 初始化:執行類構造器<client>()方法過程,比如上面的靜態變量val會被賦值爲111

16. 類卸載條件?

類卸載即該類的class對象被GC

  1. 該類的所有的實例對象都被GC,即堆中不存在該類的實例對象
  2. 該類沒有在其他地方被引用
  3. 該類的類加載器的實例已被GC
17. 什麼是雙親委派模型,爲什麼使用?

參考:

JVM 出現 fullGC 很頻繁,怎麼去線上排查問題

堆內存佔用很小 但是 JVM 頻繁full gc 問題排查

JVM面試題整理

深入理解Java虛擬機(第2版)

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