JVM full gc 觸發原因總結

目錄

1. 背景介紹

2. 什麼是full gc

3. 垃圾回收算法

4. cms (full gc)觸發原因

 

1. 背景介紹

C或者C++的內存申請和銷燬需要程序員自己控制,很容易內存泄漏和內存溢出且出現問題查找困難。Java在內存管理的優勢在於jvm自己申請和銷燬內存,不需要程序員關注內存問題,更專注於業務邏輯。那爲什麼我們還需要理解JVM的內存管理機制和原理呢?第一、作爲有追求的程序猿應該追根刨底,做到知自知彼;第二、當內存管理成爲系統性能瓶頸時或者出現內存泄漏、內存溢出問題,程序猿只有瞭解JVM的內存原理才能夠去優化和查找內存問題。第三,我們可能會遇到因爲jvm內存回收,正常業務出現卡頓。

由於jvm內容非常之多,這一小節只分析full gc場景產生的原因和如何解決

2. 什麼是full gc

這個要從jvm如何管理內存說起,當代主流虛擬機(Hotspot VM)的垃圾回收都採用“分代回收”的算法。“分代回收”是基於這樣一個事實:對象的生命週期不同,所以針對不同生命週期的對象可以採取不同的回收方式,以便提高回收效率。

① 新生代(Young Generation):大多數對象在新生代中被創建,其中很多對象的生命週期很短。每次新生代的垃圾回收(又稱Minor GC)後只有少量對象存活,所以選用複製算法,只需要少量的複製成本就可以完成回收。

新生代內又分三個區:一個Eden區,兩個Survivor區(一般而言),大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被複制到兩個Survivor區(中的一個)。當這個Survivor區滿時,此區的存活且不滿足“晉升”條件的對象將被複制到另外一個Survivor區。對象每經歷一次Minor GC,年齡加1,達到“晉升年齡閾值”後,被放到老年代,這個過程也稱爲“晉升”。顯然,“晉升年齡閾值”的大小直接影響着對象在新生代中的停留時間,在Serial和ParNew GC兩種回收器中,“晉升年齡閾值”通過參數MaxTenuringThreshold設定,默認值爲15。

② 老年代(Old Generation):在新生代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代,該區域中對象存活率高。老年代的垃圾回收(又稱Major GC)通常使用“標記-清理”或“標記-整理”算法。整堆包括新生代和老年代的垃圾回收稱爲Full GC(HotSpot VM裏,除了CMS之外,其它能收集老年代的GC都會同時收集整個GC堆,包括新生代)。

③ 永久代(Perm Generation):主要存放元數據,例如Class、Method的元信息,與垃圾回收要回收的Java對象關係不大。相對於新生代和年老代來說,該區域的劃分對垃圾回收影響比較小。

各分區的大小對GC的性能影響很大。如何將各分區調整到合適的大小,這個很有講究,涉及到jvm調優層面的內容,就不細講了。(一般是參考活躍數據來設置各個區的大小)

講了這麼多,終於入題了,那麼什麼是full gc 呢,網上其實有很多解讀,我們本文暫時以老年代的垃圾回收稱之爲full gc。(嚴格來說不算)

 

3. 垃圾回收算法

老年代垃圾回收算法,互聯網企業一般都採取cms(Concurrent Mark Sweep) 因爲其高併發、高響應的特點,CMS是基於標記-清除算法實現的。具體有哪些算法,這裏不細講,cms也是有缺點的:

a.CMS收集器對CPU資源非常敏感,在併發階段雖然不會導致用戶停頓,但是會佔用CPU資源而導致應用程序變慢,總吞吐量下降。

b.CMS收集器無法處理浮動垃圾,可能出現“Concurrnet Mode Failure”,失敗而導致另一次的Full GC。

c.CMS收集器是基於標記-清除算法的實現,因此也會產生碎片。

由於cms有這些缺點,而其他算法更不爭氣,於是出現了G1。相比CMS收集器有不少改進,首先,基於標記-壓縮算法,不會產生內存碎片,其次可以比較精確的控制停頓。jdk1.9默認G1

垃圾算法選擇依據:

曾經有講過在heap size<=3G的情況下完全不要考慮CMS GC,在heap size>3G的情況下也優先選擇ParallelOldGC,而不是CMS GC,只有在暫停時間無法接受的情況下才考慮CMS GC(不過當然,一般來說在heap size>8G後基本上都得選擇CMS GC

4. cms (full gc)觸發原因

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