Java的垃圾回收是一個面試必問題,只要按照下面的步驟回答肯定不會有大問題。
1.先告訴面試官垃圾回收分為兩大步:
a.識別哪些對象是"垃圾"(不再被使用的對象)
b.回收這些垃圾對象占用的內存空間
2. 接下來分別介紹標記階段和回收階段的細節
標記階段(比較簡單,兩句話):
從GC Roots(包括虛擬機棧、本地方法棧、方法區中的靜態屬性、常量等引用)開始遍歷;
被GC Roots直接或間接引用到的對象標記為存活,其他的就是垃圾
清除階段(回答重點,有多種算法實現):
標記-清除算法:
直接清除被標記為垃圾的對象【簡單直接,但是會產生內存碎片】
標記-整理算法:
將所有存活對象向內存的一端移動,然后清理界外內存【避免內存碎片,但是對象移動的成本比較高】
復制算法
將內存分成兩塊,只使用其中一塊,GC時將存活對象復制到另一塊【無碎片,高效;但是內存利用率只有50%】
上面三種基礎算法,但是現在常用垃圾收集器都是綜合使用上面的算法,也就是:
分代收集
把整個堆空間進行劃分,分為新生代 & 老年代 & 元空間【本地內存】
新生代 (存活的對象少)
使用復制算法
Eden和Survivor 區 新對象在Eden區;Eden區滿出發Minor G(理想間隔1-5分鐘,<100ms),存活對象移動的Survivour 區,Survivor區間內分兩個空間,回收的時候互相多次復制(默認15次)后晉升到老年代
老年代
使用標記-清除或標記-整理算法
存放長期存活的對象
當老年代空間不足時觸發Major GC/Full GC(應極少發生(<1次/天;<1s))
3.拓展部分
常用的調優手段:
1.web開發一般用G1作為垃圾回收期比較多(-XX:+UseG1GC)
2.怎么確認GC 是否有異常:
打印GC日志,看GC頻率是否正常
(-Xloggc:/path/to/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+PrintTenuringDistribution)
3. jmap 命令
4.調整新生代的比例
短生命周期對象多的應用:增大新生代(NewRatio=1)
長生命周期對象多的應用:減小新生代(NewRatio=3)
-XX:NewRatio=2(新生代:老年代=1:2)