JVM系列筆記目錄
- 虛擬機的基礎概念
- class文件結構
- class文件加載過程
- jvm內存模型
- JVM常用指令
- GC與調優
GC基礎知識
-
什么是垃圾
沒有任何引用指向的一個對象或多個對象(循環引用)
-
如何找到垃圾
- 引用計數(ReferenceCount),缺點:無法解決循環引用
- 根可達算法(RootSearching),從根開始查找,找到對象是有用的,找不到的對象為垃圾。
什么是根? 注意結合上一篇博客 JVM系列【5】JVM常用指令-運行時數據區進行理解。
- 線程棧變量 JVM Stack、native method stack
- 靜態變量 static refercences in method area、Clazz
- 常量池 runtime cosntant pool
- JNI指針 c/c++ 指針
-
常見的垃圾回收算法
- 標記清除(mark sweep)
缺點:位置不連續,產生碎片,效率偏低(需要進行兩遍掃描)
適用情況:算法相對簡單,適用於存活對象比較多的情況
-
拷貝算法 (copying)
說明:沒有碎片,浪費空間,復制移動對象,需要調整對象引用
適用情況:適用於存活對象較少的情況 只掃描一次
-
標記壓縮(mark compact)
說明:沒有碎片,效率偏低(兩遍掃描,指針需要調整)
-
JVM堆內存分代模型(用於分代垃圾回收算法)
堆內存分代模型是部分垃圾回收器使用的模型,除Epsilon ZGC Shenandoah 之外的GC都使用邏輯分代模型,但是G1 是邏輯分代 物理不分代,除此之外都是邏輯分代 而且物理分代。
分代模型中,分新生代和老年代,比例是1:2
-
新生代 = Eden區+ 2個survivor區
YGC回收后,大多數的對象會被回收,活着的進入s0;
再次YGC,活着的對象eden+s0 進入s1;
再次YGC,活着的對象eden+s1 進入s0;
年齡足夠進入老年代,一般垃圾回收器是15,CMS是6;為什么一般垃圾回收器分代年齡是15?參考下 JVM系列【4】內存模型-對象頭的內容有哪些,對象頭中4位標識GC年齡,所以最大的年齡是
2^4 -1 = 15
;s 區裝不下,直接進入老年代。
-
老年代: 存放一些"頑固對象",老年代滿了或是分配不下了會觸發FCG。
-
永久代(Permanent Generation,JDK1.7以前)/元數據區(MetaSpace,JDK1.8以后):存放的是Class文件結構,永久代必須指定大小限制 ,元數據可以設置也可以不設置,無上限(受限於物理內存),字符串常量在1.7以前存放在永久代,1.8以后存放在堆中。
-
-
垃圾回收類型和對象分配過程
-
垃圾回收類型
上一個點解釋了堆內存分代模型,這里統一下概念:MinorGC=YGC指的是新生代即Y區的垃圾回收,MajorGC=FGC指的是老年代分配不下或是滿了發生的GC,包括新生代和老年代。
-
對象如何分配
在之前的博客中 JVM系列【4】內存模型-new Object()面試6連問-對象如何分配,簡單提過這一點。
-
對照流程圖,分配過程:
> 1. new對象后優先在棧上分配,棧上分配的對象`pop`后就消失;
> 2. 是否是大對象(Y區分配不下的對象)?是就分配到O區,O區發生FGC后回收
> 3. 不是大對象,優先分配TLAB(Thread Local Allocation Buffer線程本地分配緩存)上,分配不下就分配到Eden區 。
-
了解棧上分配、TLAB、分配擔保機制和升代
-
哪些對象棧上分配?
線程私有對象 、無逃逸對象即離開代碼塊就沒有引用的對象、支持標量替換的對象,如類中變量可以用基本變量替換。
-
線程本地分配Thread Local Allocation Buffer
獨占eden空間,默認1%;多線程時候不用競爭eden就可以申請空間,提高效率;可分配小對象 -
分配擔保機制
在新生代無法分配內存的時候,把新生代的對象轉移到老生代,然后把新對象放入騰空的新生代。參考
-
對象何時進入老年代?
超過MaxTenuringThreshold指定的次數;
根據動態年齡計算進入老年代,Survivor空間中年齡從小到大的對象進行累加,當加入某個年齡段后,累加和超過survivor區域*TargetSurvivorRatio(默認50%)的時候,就從這個年齡段往上的年齡的對象進行晉升到老年代。參考
-
-
常見的垃圾回收器
常見的垃圾回收器有Serial/SerialOld、ParallelScavenge/ParallelOld、ParNew/CMS、G1、ZGC、Shenandoah、Epsilon。Serial/SerialOld、ParallelScavenge/ParallelOld、ParNew/CMS是分代的垃圾回收器,G1是邏輯上分代物理上不分代,ZGC和Shenandoah是不分代,Epsilon是JDK調試用的垃圾回收器。
歷史:JDK誕生,Serial追隨,為了提供效率誕生PS,為配合CMS,誕生PN,CMS是1.4后期引入的,CMS是里程碑式的GC,但是CMS毛病比較多,因此目前沒有任何一個JDK版本默認CMS。
-
Serial
年輕代 串行回收
-
SerialOld
老年代 串行回收
-
PS(ParallelScavenge)
年輕代 並行回收
-
PO(ParallelOld)
老年代 並行回收
-
PN(ParNew)
年輕代 增強版PS配合CMS的並行回收。PN 和 PS區別?PN 響應時間優先;PS吞吐量優先
-
CMS(ConcurrentMarkSweep)
老年代並發的,垃圾回收和應用程序同時運行,降低STW的時間(200ms);
CMS問題比較多,所以現在沒有一個版本默認是CMS,只能手工指定;
CMS既然是MarkSweep,就一定會有碎片化的問題,碎片到達一定程度,CMS的老年代分配對象分配不下的時候,使用SerialOld 進行老年代回收,STW無法忍受;
- 如何解決碎片化:設定
-XX:+UseCMSCompactAtFullCollection
默認開啟;設定-XX:CMSFullGCsBeforeCompaction
,默認為0 指經過多少次FGC才進行壓縮。 - 浮動垃圾問題解決?降低觸發CMS的閾值,保持老年代有足夠的空間;參數
-XX:CMSInitiatingOccupancyFraction
指定使用CMS時老年代使用了指定閾值的內存后觸發FGC,建議68-92%
使用的算法:三色標記+Increamental Update
- 如何解決碎片化:設定
-
G1
STW可以達到10ms
算法:三色標記+SATB
-
ZGC
STW號稱可以達到1ms
算法:顏色指針ColoredPointers + LoadBarrier
-
Shenandaoh
算法:ColoredPointers + WriteBarrier
-
垃圾回收器和內存大小的關系
Serial 幾十兆
PS 上百兆-幾個G
CMS 20G左右
G1 上百G
ZGC 4T-16T(JDK13可以支持)
知識分享,轉載請注明出處。學無先后,達者為先!