1. 程式人生 > >聊聊JVM(四)深入理解Major GC, Full GC, CMS

聊聊JVM(四)深入理解Major GC, Full GC, CMS

很多人都分不清Major GC, Full GC的概念,事實上我查了下資料,也沒有查到非常精確的Major GC和Full GC的概念定義。分不清這兩個概念可能就會對這個問題疑惑:Full GC會引起Minor GC嗎?

經過一系列的查詢和對JVM表現的分析,基本可以給Full GC和Major GC下一個定義了,這篇說一說概念和理由。

我們可以認為Major GC == Full GC,他們是一個概念,就是針對老年代/永久代進行GC。因為取名叫Full就會讓人疑惑,到底會不會先Minor GC。事實上Full GC本身不會先進行Minor GC,我們可以配置,讓Full GC之前先進行一次Minor GC,因為老年代很多物件都會引用到新生代的物件,先進行一次Minor GC可以提高老年代GC的速度。比如老年代使用CMS時,設定CMSScavengeBeforeRemark優化,讓CMS remark之前先進行一次Minor GC。

弄清楚了Full GC本意單純就是針對老年代了之後,我們再進一步深入理解Full GC的含義。因為CMS主要可以分為initial mark(stop the world), concurrent mark, remark(stop the world), concurrent sweep幾個階段,其中initial mark和remark會stop the world。

在這篇聊聊JVM(二)說說GC的一些常見概念 我們說了一次CMS至少會給Full GC的次數 + 2,因為Full GC的次數是按照老年代GC時stop the world的次數而定的

再來看Full GC的Time的定義,可以理解它也指的是老年代GC時stop the world的時間

。我們看一個例項來證明一下。

這段日誌是我從一個tomcat的JVM GC日誌中抓取的,老年代使用了CMS收集器

2014-12-08T17:24:18.514+0800: 77443.326: [GC [1 <strong><span style="color:#FF0000;">CMS-initial-mark: 1382782K(1843200K)] 1978934K(4710400K), 0.0702700 secs] [Times: user=0.07 sys=0.00, real=0.07 secs]</span></strong> 
2014-12-08T17:24:18.586+0800: 77443.398: [CMS-concurrent-mark-start]
2014-12-08T17:24:19.890+0800: 77444.702: [CMS-concurrent-mark: 1.206/1.303 secs] [Times: user=2.80 sys=0.07, real=1.30 secs] 
2014-12-08T17:24:19.890+0800: 77444.702: [CMS-concurrent-preclean-start]
2014-12-08T17:24:19.906+0800: 77444.718: [CMS-concurrent-preclean: 0.015/0.015 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
2014-12-08T17:24:19.906+0800: 77444.718: [CMS-concurrent-abortable-preclean-start]
 CMS: abort preclean due to time 2014-12-08T17:24:25.181+0800: 77449.993: [CMS-concurrent-abortable-preclean: 5.241/5.275 secs] [Times: user=6.03 sys=0.09, real=5.27 secs] 
2014-12-08T17:24:25.187+0800: 77449.999: [GC[YG occupancy: 749244 K (2867200 K)]77450.000: [Rescan (parallel) , 0.0276780 secs]77450.028: [weak refs processing, 0.2029030 secs]
 [<span style="color:#FF0000;"><strong>1 CMS-remark: 1382782K(1843200K)] 2132027K(4710400K), 0.2340660 secs] [Times: user=0.43 sys=0.00, real=0.23 secs</strong></span>] 
2014-12-08T17:24:25.424+0800: 77450.236: [CMS-concurrent-sweep-start]
2014-12-08T17:24:27.420+0800: 77452.232: [CMS-concurrent-sweep: 1.918/1.996 secs] [Times: user=2.61 sys=0.05, real=2.00 secs] 
2014-12-08T17:24:27.421+0800: 77452.233: [CMS-concurrent-reset-start]
2014-12-08T17:24:27.430+0800: 77452.242: [CMS-concurrent-reset: 0.010/0.010 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
2014-12-09T12:45:05.545+0800: 147090.358: [GC [<span style="color:#FF0000;"><strong>1 CMS-initial-mark: 1384080K(1843200K)] 2013429K(4710400K), 0.0656230 secs] [Times: user=0.06 sys=0.00, real=0.07 secs</strong></span>] 
2014-12-09T12:45:05.613+0800: 147090.425: [CMS-concurrent-mark-start]
2014-12-09T12:45:06.848+0800: 147091.660: [CMS-concurrent-mark: 1.196/1.235 secs] [Times: user=2.77 sys=0.03, real=1.23 secs] 
2014-12-09T12:45:06.849+0800: 147091.661: [CMS-concurrent-preclean-start]
2014-12-09T12:45:06.862+0800: 147091.674: [CMS-concurrent-preclean: 0.013/0.013 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
2014-12-09T12:45:06.862+0800: 147091.674: [CMS-concurrent-abortable-preclean-start]
 CMS: abort preclean due to time 2014-12-09T12:45:11.874+0800: 147096.686: [CMS-concurrent-abortable-preclean: 4.948/5.012 secs] [Times: user=6.04 sys=0.10, real=5.01 secs] 
2014-12-09T12:45:11.882+0800: 147096.694: [GC[YG occupancy: 815312 K (2867200 K)]147096.695: [Rescan (parallel) , 0.0476710 secs]147096.743: [weak refs processing, 0.1565260 secs] 
[1 <span style="color:#FF0000;"><strong>CMS-remark: 1384080K(1843200K)] 2199393K(4710400K), 0.2064660 secs] [Times: user=0.48 sys=0.00, real=0.20 secs</strong></span>] 
2014-12-09T12:45:12.091+0800: 147096.903: [CMS-concurrent-sweep-start]
2014-12-09T12:45:14.078+0800: 147098.890: [CMS-concurrent-sweep: 1.934/1.986 secs] [Times: user=2.43 sys=0.04, real=1.99 secs] 
2014-12-09T12:45:14.078+0800: 147098.890: [CMS-concurrent-reset-start]
2014-12-09T12:45:14.084+0800: 147098.896: [CMS-concurrent-reset: 0.006/0.006 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

我把CMS的initial mark和remark的日誌都標記了。

我們可以看到總共發生了兩次CMS,所以Full GC的次數應該是4

Full GC的時間 = 0.07 secs(第一次initial mark)+ 0.23 secs(第一次remark) + 0.07 secs(第二次initial mark) + 0.20 secs(第二次remark) = 0.57s

用jstat -gc 得到的時間Full GC的次數和時間也是吻合的。


所以jstat是Java官方提供的工具,所以我們可以說得出的結論是和官方的一致的。

下面是Visual GC的截圖,看Old Gen的統計資料: 4 collections, 576.421ms


再來看一個更加直接的例子,從OpenJDK裡面找線索:

這段程式碼來自openjdk/hotspot/src/share/vm/services/memoryService.cpp,從程式碼中可以看到JVM使用了一個_fullGC的布林值來表示是否是Full GC

DefNew, ParNew, ASParNew都是新生代的收集器演算法,當使用它們時,_fullGC = false

MarkSweepCompact(Serial Old收集器), ConcurrentMarkSweep(CMS), ASConcurrentMarkSweep時_fullGC = true。所以只有收集老年代的時候,才算Full GC




我們可以安全的說:

1. Full GC == Major GC指的是對老年代/永久代的stop the world的GC

2. Full GC的次數 = 老年代GC時 stop the world的次數

3. Full GC的時間 = 老年代GC時 stop the world的總時間

4. CMS 不等於Full GC,我們可以看到CMS分為多個階段,只有stop the world的階段被計算到了Full GC的次數和時間,而和業務執行緒併發的GC的次數和時間則不被認為是Full GC

我們可以看到正常的CMS的stop the world的時間很短,都是在幾十到幾百ms的級別,對Full GC的時間影響很小。但是有時候我們用jstat看到的Full GC的時間很長。比如下面這個例子,和上面的Tomcat是同一個應用,只是是我調優之前的資料。


我們看到調優之前的Full GC的評價時間 = 1188 / 223 = 5秒,也就是說單次Full GC的stop the world的時間達到了5s! 進一步分析日誌,得到如下日誌:

54090.152: [Full GC (System) 54090.153: [CMS: 1211220K->1428569K(4096000K), 5.4936890 secs] 3483935K->1428569K(7168000K), 
[CMS Perm : 148045K->147921K(262144K)], 5.4963160 secs] [Times: user=5.50 sys=0.00, real=5.50 secs] 
57696.218: [Full GC (System) 57696.219: [CMS: 1513461K->1213731K(4096000K), 4.7293810 secs] 3283076K->1213731K(7168000K), 
[CMS Perm : 148019K->147881K(262144K)], 4.7317730 secs] [Times: user=4.73 sys=0.00, real=4.74 secs] 
61301.483: [Full GC (System) 61301.484: [CMS: 1288630K->968887K(4096000K), 4.5720170 secs] 2466308K->968887K(7168000K), 
[CMS Perm : 147996K->147835K(262144K)], 4.5743720 secs] [Times: user=4.57 sys=0.00, real=4.57 secs] 
64906.588: [Full GC (System) 64906.590: [CMS: 1026456K->1568407K(4096000K), 5.0347600 secs] 3769961K->1568407K(7168000K), 
[CMS Perm : 148004K->147903K(262144K)], 5.0373410 secs] [Times: user=5.02 sys=0.00, real=5.04 secs] 
68512.160: [Full GC (System) 68512.161: [CMS: 1631217K->838700K(4096000K), 4.7239290 secs] 2552874K->838700K(7168000K), 
[CMS Perm : 148017K->147829K(262144K)], 4.7261610 secs] [Times: user=4.72 sys=0.00, real=4.72 secs] 
72117.421: [Full GC (System) 72117.423: [CMS: 905025K->1529502K(4096000K), 5.3562640 secs] 3556285K->1529502K(7168000K), 
[CMS Perm : 148049K->147945K(262144K)], 5.3587790 secs] [Times: user=5.36 sys=0.00, real=5.36 secs] 

我們看到是System.gc引起的Full GC,而老年代的GC時間到達了5秒多,它顯示的是CMS,但是實際上不是CMS併發的收集器,而是CMS發生了concurrent mode fail之後退化成了Serial Old收集器,它是單執行緒的標記-壓縮收集器,所以耗時非常的長。

最後再次強調一下結論:

1. Full GC == Major GC指的是對老年代/永久代的stop the world的GC

2. Full GC的次數 = 老年代GC時 stop the world的次數

3. Full GC的時間 = 老年代GC時 stop the world的總時間

4. CMS 不等於Full GC,我們可以看到CMS分為多個階段,只有stop the world的階段被計算到了Full GC的次數和時間,而和業務執行緒併發的GC的次數和時間則不被認為是Full GC

5. Full GC本身不會先進行Minor GC,我們可以配置,讓Full GC之前先進行一次Minor GC,因為老年代很多物件都會引用到新生代的物件,先進行一次Minor GC可以提高老年代GC的速度。比如老年代使用CMS時,設定CMSScavengeBeforeRemark優化,讓CMS remark之前先進行一次Minor GC。

相關推薦

聊聊JVM深入理解Major GC, Full GC, CMS

很多人都分不清Major GC, Full GC的概念,事實上我查了下資料,也沒有查到非常精確的Major GC和Full GC的概念定義。分不清這兩個概念可能就會對這個問題疑惑:Full GC會引起Minor GC嗎? 經過一系列的查詢和對JVM表現的分析,基本可以給Fu

shiro的源碼學習-- 深入理解realm

instance his face 成功 返回 void exce gen 調用 IniRealm的類結構如下圖: 下面分析每個類: (1)Ream: 域的頂點,其代碼如下:securityManager會使驗證器來調用,驗證器通過Realm返回用戶信息,確定用戶是否登錄

聊聊併發深入分析ConcurrentHashMap

術語定義 術語 英文 解釋 雜湊演算法 hash algorithm 是一種將任意內容的輸入轉換成相同長度輸出的加密方式,其輸出被稱為雜湊值。 雜湊表 hash table 根據設定的雜湊函式H(key)和處理衝突方法將一組關鍵字映象到一個有限的地址區間上,並以關鍵字在地址區間

聊聊高並發二十解析java.util.concurrent各個組件 深入理解AQS

sar 成功 通知 ati help write ng- ads 同步 近期總體過了下AQS的結構。也在網上看了一些講AQS的文章,大部分的文章都是泛泛而談。又一次看了下AQS的代碼,把一些新的要點拿出來說一說。 AQS是一個管程。提供了一個主要的同步器的

深入理解JVM——各個版本提供的垃圾收集器

上一篇將的回收演算法是記憶體回收的方法論,本篇講垃圾收集器的具體實現,Java虛擬機器規範並沒有對齊做出規定和限制,所以不同廠商,不同版本的虛擬機器,垃圾收集器有很大的區別。 收集器名稱 區域 說明

聊聊高併發二十解析java.util.concurrent各個元件 深入理解AQS

最近整體過了下AQS的結構,也在網上看了一些講AQS的文章,大部分的文章都是泛泛而談。重新看了下AQS的程式碼,把一些新的要點拿出來說一說。 AQS是一個管程,提供了一個基本的同步器的能力,包含了一個狀態,修改狀態的原子操作,以及同步執行緒的一系列操作。它是CLHLock

深入理解jvm:虛擬機器位元組碼執行引擎

執行時棧幀 每一個方法從呼叫開始到執行完成都對應著一張棧幀的進棧和出棧。棧幀中儲存著區域性變量表,運算元表,動態連結和方法返回地址。位於虛擬機器最頂層的稱為當前方法棧。 區域性變量表 儲存當前方法的區域性變數和引數,區域性變量表的容量以變數槽slo

理解JVMJVM類載入機制

Class檔案 我們寫的Java程式碼,經過編譯器編譯之後,就成為了.class檔案,從本地機器碼變成了位元組碼。Class檔案是一組以8位位元組為基礎單位的二進位制流,各個資料專案嚴格按照順序緊湊地排列在Class檔案之中,中間沒有新增任何分隔符,這使得整個

聊聊JVM相對全面的GC總結(轉)

cor war 性能 依靠 blank 知識 flags 要去 內存空間 轉至:http://blog.csdn.net/iter_zc/article/details/41746265 最近時間比較緊張,要寫的東西也有很多,只能想到一點寫一點。關於GC,網上的資料太多,之

轉載深入理解java的接口和抽象類

final類 轉載 如何實現 靜態 參考 種類型 tar 發現 是否 本文轉自地址:http://www.cnblogs.com/dolphin0520/p/3811437.html 作者:海子 出處:http://www.cnblogs.com/dolphin0520/

java內存模型深入理解java內存模型的系列好文

總結 nal href ola down 深入理解 ati markdown vol 深入理解java內存模型(一)——基礎深入理解java內存模型(二)——重排序深入理解java內存模型(三)——順序一致性深入理解java內存模型(四)——volatile深入理解java

Java核心深入理解執行緒池ThreadPool

本文你將獲得以下資訊: 執行緒池原始碼解讀 執行緒池執行流程分析 帶返回值的執行緒池實現 延遲執行緒池實現 為了方便讀者理解,本文會由淺入深,先從執行緒池的使用開始再延伸到原始碼解讀和原始碼分析等高階內容,讀者可根據自己的情況自主選擇閱讀順序和需要了解的章節。 一、執行緒池優點

PyTorch基礎系列——深入理解autograd:Variable屬性方法【最新已經和tensor合併為一類】

torch.autograd.backward(variables, grad_variables, retain_variables=False) 當前Variable對leaf variable求偏導。 計算圖可以通過鏈式法則求導。如果Variable是 非標量(non-scalar

Java核心深入理解BIO、NIO、AIO

導讀:本文你將獲取到:同/非同步 + 阻/非阻塞的效能區別;BIO、NIO、AIO 的區別;理解和實現 NIO 操作 Socket 時的多路複用;同時掌握 IO 最底層最核心的操作技巧。 BIO、NIO、AIO 的區別是什麼? 同/非同步、阻/非阻塞的區別是什麼? 檔案讀寫最優雅的實現方式是什

Numpy入門深入學習Numpy模組

1 linalg模組 import numpy as np A = np.mat("0 1 2; 1 0 3; 4 -3 8") A matrix([[ 0, 1, 2], [ 1, 0, 3], [ 4, -3, 8]])

從資料結構深入理解資料庫的索引

樹 二叉樹 性質: 1. 在非空二叉樹中,第ii層的結點總數不超過2i−12i−1, i>=1i>=1; 2. 深度為hh的二叉樹最多有2h−12h−1個結點(h>=1),最少有h個結點; 3. 對於任意一棵二叉樹,如果其葉結點數為N

JVMGC演算法

1、物件與引用 為了解決“哪些記憶體需要回收”的問題,需要確定哪些物件是“有用不可回收”的,而哪些物件是“無用可回收”的。通常存在以下兩種判斷演算法。 引用計數法 演算法原理:給物件新增一個引用計數器,每當一個地方引用它時,計數器值就加1;每當一個引用失效時,計數器值就減1;當引用

Zabbix監控平臺深入理解zabbix

一,Zabbix Web操作深入   1.1 Zabbix Web下的主機和模版以及監控項的新增方式   (1)建立一個模版 我們所有的功能幾乎都是在模版中定義的 我們再點進新建立的模版檢視 模版裡幾乎可以設定我們需要的所有功能

Zabbix監控平臺3.2.4深入理解zabbix

一,Zabbix Web操作深入   1.1 Zabbix Web下的主機和模版以及監控項的新增方式 (1)建立一個模版 我們所有的功能幾乎都是在模版中定義的 我們再點進新建立的模版檢視 模版裡幾乎可以設定我們需要的所有功能 (2)在模版裡建立

深度學習基礎系列| 深入理解交叉熵函式及其在tensorflow和keras中的實現

  在統計學中,損失函式是一種衡量損失和錯誤(這種損失與“錯誤地”估計有關,如費用或者裝置的損失)程度的函式。假設某樣本的實際輸出為a,而預計的輸出為y,則y與a之間存在偏差,深度學習的目的即是通過不斷地訓練迭代,使得a越來越接近y,即 a - y →0,而訓練的本質就是尋找損失函式最小值的過程。   常見的