JVM之垃圾收集(Garbage Collection [Ⅱ])
阿新 • • 發佈:2020-06-24
7 個垃圾收集器
垃圾收集器就是記憶體回收操作的具體實現,HotSpot 有 7 種。因為它們各有各的適用場景。有的屬於新生代收集器,有的屬於老年代收集器,所以一般都是搭配使用的。關於它們的簡單介紹以及分類請見下圖。
Serial 收集器
特點:
1.“單執行緒”操作。會產生“Stop The World”。
2.採用"Stopr the world"。
3.Serial 收集器是虛擬機器器在 Client模式下的預設新生代收集器,它的優勢是簡單高效,適合單 CPU 模式。
複製程式碼
ParNew 收集器
1.其本身就是 Serial 收集器的多執行緒版本。雖然除此之外沒什麼創新之處,但它卻是許多執行在 Server 模式下的虛擬機器器中的首選新生代收集器。
2.除了 Serial 收集器外,只有它能和 CMS 收集器搭配使用。
複製程式碼
Parallel Scavenge 收集器
1.新生代收集器,並行的多執行緒收集器。
2.使用複製演演算法,
3.可控制吞吐量(Throughput)。
複製程式碼
吞吐量 = 執行使用者程式碼時間 / ( 執行使用者程式碼時間 + 垃圾收集時間 )
可調節的虛擬機器器引數:
-
-XX:MaxGCPauseMillis
:最大 GC 停頓的秒數; -
-XX:GCTimeRatio
:吞吐量大小,一個 0 ~ 100 的數,最大 GC 時間佔總時間的比率 = 1 / (GCTimeRatio + 1)
; -
-XX:+UseAdaptiveSizePolicy
:一個開關引數,開啟後就無需手工指定-Xmn
-XX:SurvivorRatio
等引數了,虛擬機器器會根據當前系統的執行情況收集效能監控資訊,自行調整。
Serial Old 收集器
1.Serial收集器的老年代版,同為單執行緒。
2.使用標記整理演演算法。
3.作為CMS收集容器的後備預案。
複製程式碼
Prallel Old 收集器
1.Parallel Old收集器的老年代版,多執行緒。
2.使用標記-整理演演算法。
複製程式碼
CMS 收集器(Concurrent Mark Sweep)
特點:
1.CMS注重於服務的響應速度,希望系統停頓時間最短。
2.基於“標記-清除”演演算法實現的。【注1】
3.存在以下幾點缺點:
(1)CMS收集器對CPU資源非常敏感。
(2)CMS收集器無法處理浮動垃圾。
(3)由於基於標記-清除演演算法,所以會產生大量碎片
複製程式碼
【注1】 標記-清除演演算法步驟: 1.初始標記 2.併發標記 3.重新標記 4.併發清除
引數設定:
-
-XX:+UseCMSCompactAtFullCollection
:在 CMS 要進行 Full GC 時進行記憶體碎片整理(預設開啟) -
-XX:CMSFullGCsBeforeCompaction
:在多少次 Full GC 後進行一次空間整理(預設是 0,即每一次 Full GC 後都進行一次空間整理)
關於 CMS 使用 標記 - 清除 演演算法的一點思考:
之前對於 CMS 為什麼要採用 標記 - 清除 演演算法十分的不理解,既然已經有了看起來更高階的 標記 - 整理 演演算法,那 CMS 為什麼不用呢?最近想了想,感覺可能是這個原因,不過也不是很確定,只是個人的一種猜測。
標記 - 整理 會將所有存活物件向一端移動,然後直接清理掉邊界以外的記憶體。這就意味著需要一個指標來維護這個分隔存活物件和無用空間的點,而我們知道 CMS 是併發清理的,雖然我們啟動了多個執行緒進行垃圾回收,不過如果使用 標記 - 整理 演演算法,為了保證執行緒安全,在整理時要對那個分隔指標加鎖,保證同一時刻只有一個執行緒能修改它,加鎖的這一過程相當於將並行的清理過程變成了序列的,也就失去了並行清理的意義了。
所以,CMS 採用了 標記 - 清除 演演算法。
G1 收集器
特點: 1.並行併發。 2.分代收集。 3.空間整合。 4.可預測的停頓。
G1運算步驟
1.初始標記
2.併發標記
3.最終標記
4.篩選回收
複製程式碼
GC 日誌解讀
Java 記憶體分配策略
新生代和老年代的 GC 操作:
- 新生代 GC 操作:Minor GC
- 發生的非常頻繁,速度較塊。
- 老年代 GC 操作:Full GC / Major GC
- 經常伴隨著至少一次的 Minor GC;
- 速度一般比 Minor GC 慢上 10 倍以上。
優先在 Eden 區分配
- Eden 空間不夠將會觸發一次 Minor GC;
- 虛擬機器器引數:
-
-Xmx
:Java 堆的最大值; -
-Xms
:Java 堆的最小值; -
-Xmn
:新生代大小; -
-XX:SurvivorRatio=8
:Eden 區 / Survivor 區 = 8 : 1
-
大物件直接進入老年代
- 大物件定義: 需要大量連續記憶體空間的 Java 物件。例如那種很長的字串或者陣列。
-
設定物件直接進入老年代大小限制:
-
-XX:PretenureSizeThreshold
:單位是位元組;- 只對 Serial 和 ParNew 兩款收集器有效。
- 目的: 因為新生代採用的是複製演演算法收集垃圾,大物件直接進入老年代可以避免在 Eden 區和 Survivor 區發生大量的記憶體複製。
-
長期存活的物件將進入老年代
-
固定物件年齡判定: 虛擬機器器給每個物件定義一個年齡計數器,物件每在 Survivor 中熬過一次 Minor GC,年齡 +1,達到
-XX:MaxTenuringThreshold
設定值後,會被晉升到老年代,-XX:MaxTenuringThreshold
預設為 15; - 動態物件年齡判定: Survivor 中有相同年齡的物件的空間總和大於 Survivor 空間的一半,那麼,年齡大於或等於該年齡的物件直接晉升到老年代。