摘要:分代概念以及不同的算法超出了了此次討論的范圍。在標(biāo)記期間區(qū)引用的區(qū)對(duì)象的對(duì)象會(huì)被忽略。不可否認(rèn)的是新生代中的一些對(duì)象被錯(cuò)誤當(dāng)成垃圾而不會(huì)被移動(dòng)到區(qū)。結(jié)論綜合情況來(lái)看,這是避免考慮項(xiàng)目中的最好方式。
原文出處:Minor GC vs Major GC vs Full GC
在Plumbr的工作過(guò)程中遇到GC間隙功能探測(cè)問(wèn)題使我不得不關(guān)注相關(guān)文章,書(shū)籍,簡(jiǎn)報(bào)。自始至終,我不止一次迷惑于 Minor, Major and Full GC 的用法。為了搞清楚這些疑惑我寫(xiě)這篇博客。
這篇博客期望讀者了解JVM 底層 GC機(jī)制。jvm heap區(qū) 分為 Eden,Survivor,Tenured/Old區(qū)。分代概念以及不同的GC算法超出了了此次討論的范圍。
Minor GC
新生代(由 Eden and Survivor 組成)的垃圾收集叫做Minor GC。該定義清晰易于理解。但是以下幾點(diǎn)仍然需要我們注意:
當(dāng)jvm 無(wú)法為新建對(duì)象分配內(nèi)存空間的時(shí)候Minor GC被觸發(fā),例如新生代空間被占滿(mǎn)。因此新生代空間占用率越高,Minor GC越頻繁。
當(dāng)空間被占滿(mǎn),它下面的所有對(duì)象都會(huì)被復(fù)制,而且堆頂指針從空閑空間的零位置移動(dòng)(譯者注:此處為復(fù)制算法)。因此取代傳統(tǒng)的標(biāo)記清除壓縮算法,去清理Eden區(qū)和Survivor區(qū),因此Eden和Survivor區(qū)無(wú)內(nèi)存碎片產(chǎn)生。
在Minor GC期間,實(shí)際上Tenured區(qū)被忽略,實(shí)際上Tenured區(qū)引用young區(qū)的對(duì)象被當(dāng)作GC roots。在標(biāo)記期間young區(qū)引用的Tenured區(qū)對(duì)象的對(duì)象會(huì)被忽略。
反對(duì)所有Minor GC都會(huì)觸發(fā)“stop-the-world”這一觀點(diǎn)。在大多數(shù)應(yīng)用中,忽略"stop-the-world"停留時(shí)長(zhǎng)。不可否認(rèn)的是新生代中的一些對(duì)象被錯(cuò)誤當(dāng)成垃圾而不會(huì)被移動(dòng)到Survivor/Old區(qū)。如果筆者反對(duì)的觀點(diǎn)成立,一些新生對(duì)象由于不合適被當(dāng)作垃圾,導(dǎo)致Minor GC停頓將會(huì)耗費(fèi)更多的時(shí)間。
因此Minor GC的情況相當(dāng)清楚了,每次Minor GC只清理新生代。
尋找減少GC停頓時(shí)長(zhǎng)的方式?automatically detect what causes GC pauses 可以解決你的難題。
Major GC vs Full GC
在目前的項(xiàng)目中還沒(méi)有明確的定義,這點(diǎn)需要注意。JVM規(guī)范和垃圾收集研究論文都沒(méi)有提及,但是乍一看,這些建立在我們掌握了Minor GC清理新生代上的定義并非難事:
Major GC清理Tenured區(qū)。
Full GC清理整個(gè)heap區(qū),包括Yong區(qū)和Tenured區(qū)。
不幸的是這些有點(diǎn)復(fù)雜,難于解釋。首先,Minor GC觸發(fā)Major GC,在很多情形下,將這兩者分開(kāi)是不可能的。另一方面,許多現(xiàn)代垃圾收集平臺(tái)傾向于清理Tenured區(qū),因此,用“cleaning”術(shù)語(yǔ)僅僅是部分正確。
GC無(wú)論被稱(chēng)作Major GC還是Full GC,你應(yīng)該搞清楚無(wú)論GC停止所有的應(yīng)用線(xiàn)程還是它可以和應(yīng)用線(xiàn)程同時(shí)進(jìn)行。
這個(gè)問(wèn)題甚至發(fā)生在JVM標(biāo)準(zhǔn)工具。下面是最好的解決渠道和實(shí)例,讓我們比較運(yùn)行在同一個(gè)JVM的兩個(gè)不同工具對(duì)Concurrent Mark and Sweep收集器的輸出(-XX:+UseConcMarkSweepGC)。
首先嘗試使用 jstat :
Time S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 5.7 34048.0 34048.0 0.0 34048.0 272640.0 194699.7 1756416.0 181419.9 18304.0 17865.1 2688.0 2497.6 3 0.275 0 0.000 0.275 6.7 34048.0 34048.0 34048.0 0.0 272640.0 247555.4 1756416.0 263447.9 18816.0 18123.3 2688.0 2523.1 4 0.359 0 0.000 0.359 7.7 34048.0 34048.0 0.0 34048.0 272640.0 257729.3 1756416.0 345109.8 19072.0 18396.6 2688.0 2550.3 5 0.451 0 0.000 0.451 8.7 34048.0 34048.0 34048.0 34048.0 272640.0 272640.0 1756416.0 444982.5 19456.0 18681.3 2816.0 2575.8 7 0.550 0 0.000 0.550 9.7 34048.0 34048.0 34046.7 0.0 272640.0 16777.0 1756416.0 587906.3 20096.0 19235.1 2944.0 2631.8 8 0.720 0 0.000 0.720 10.7 34048.0 34048.0 0.0 34046.2 272640.0 80171.6 1756416.0 664913.4 20352.0 19495.9 2944.0 2657.4 9 0.810 0 0.000 0.810 11.7 34048.0 34048.0 34048.0 0.0 272640.0 129480.8 1756416.0 745100.2 20608.0 19704.5 2944.0 2678.4 10 0.896 0 0.000 0.896 12.7 34048.0 34048.0 0.0 34046.6 272640.0 164070.7 1756416.0 822073.7 20992.0 19937.1 3072.0 2702.8 11 0.978 0 0.000 0.978 13.7 34048.0 34048.0 34048.0 0.0 272640.0 211949.9 1756416.0 897364.4 21248.0 20179.6 3072.0 2728.1 12 1.087 1 0.004 1.091 14.7 34048.0 34048.0 0.0 34047.1 272640.0 245801.5 1756416.0 597362.6 21504.0 20390.6 3072.0 2750.3 13 1.183 2 0.050 1.233 15.7 34048.0 34048.0 0.0 34048.0 272640.0 21474.1 1756416.0 757347.0 22012.0 20792.0 3200.0 2791.0 15 1.336 2 0.050 1.386 16.7 34048.0 34048.0 34047.0 0.0 272640.0 48378.0 1756416.0 838594.4 22268.0 21003.5 3200.0 2813.2 16 1.433 2 0.050 1.484
上面片段取自JVM啟動(dòng)17秒,以這些信息為基礎(chǔ),我們可以推斷2次Full GC之前進(jìn)行12次 Minor GC,一共耗費(fèi)50毫秒。你可以通過(guò)一些基于GUI的工具證實(shí),例如jconsole和jvisualvm。
在下結(jié)論之前,我們看一下JVM運(yùn)行g(shù)arbage collection logs。顯然-XX:+PrintGCDetails 告訴我們更多細(xì)節(jié):
java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC eu.plumbr.demo.GarbageProducer
3.157: [GC (Allocation Failure) 3.157: [ParNew: 272640K->34048K(306688K), 0.0844702 secs] 272640K->69574K(2063104K), 0.0845560 secs] [Times: user=0.23 sys=0.03, real=0.09 secs] 4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K->34048K(306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307 secs] [Times: user=0.25 sys=0.05, real=0.10 secs] ... cut for brevity ... 11.292: [GC (Allocation Failure) 11.292: [ParNew: 306686K->34048K(306688K), 0.0857219 secs] 971599K->779148K(2063104K), 0.0857875 secs] [Times: user=0.26 sys=0.04, real=0.09 secs] 12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), 0.0821774 secs] 1051788K->856120K(2063104K), 0.0822400 secs] [Times: user=0.25 sys=0.03, real=0.08 secs] 12.989: [GC (Allocation Failure) 12.989: [ParNew: 306686K->34048K(306688K), 0.1086667 secs] 1128760K->931412K(2063104K), 0.1087416 secs] [Times: user=0.24 sys=0.04, real=0.11 secs] 13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: 897364K(1756416K)] 936667K(2063104K), 0.0041705 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 13.102: [CMS-concurrent-mark-start] 13.341: [CMS-concurrent-mark: 0.238/0.238 secs] [Times: user=0.36 sys=0.01, real=0.24 secs] 13.341: [CMS-concurrent-preclean-start] 13.350: [CMS-concurrent-preclean: 0.009/0.009 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 13.350: [CMS-concurrent-abortable-preclean-start] 13.878: [GC (Allocation Failure) 13.878: [ParNew: 306688K->34047K(306688K), 0.0960456 secs] 1204052K->1010638K(2063104K), 0.0961542 secs] [Times: user=0.29 sys=0.04, real=0.09 secs] 14.366: [CMS-concurrent-abortable-preclean: 0.917/1.016 secs] [Times: user=2.22 sys=0.07, real=1.01 secs] 14.366: [GC (CMS Final Remark) [YG occupancy: 182593 K (306688 K)]14.366: [Rescan (parallel) , 0.0291598 secs]14.395: [weak refs processing, 0.0000232 secs]14.395: [class unloading, 0.0117661 secs]14.407: [scrub symbol table, 0.0015323 secs]14.409: [scrub string table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs] [Times: user=0.14 sys=0.00, real=0.05 secs] 14.412: [CMS-concurrent-sweep-start] 14.633: [CMS-concurrent-sweep: 0.221/0.221 secs] [Times: user=0.37 sys=0.00, real=0.22 secs] 14.633: [CMS-concurrent-reset-start] 14.636: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
基于這些信息,我們看到12次Minor GC 之后一些事情開(kāi)始發(fā)生,但是與上面2次Full GC不同的是老年代的不同階段只有一次GC:
初始化標(biāo)記階段,耗費(fèi)0.0041705 seconds大約4ms。為了初始化標(biāo)記這個(gè)階段進(jìn)行“stop-the-world”。
標(biāo)記和預(yù)清除并發(fā)階段,和應(yīng)用先線(xiàn)程并行執(zhí)行。
最后重復(fù)標(biāo)記階段,耗費(fèi)0.0462010 seconds大約46ms。再次進(jìn)行“stop-the-world”。
并發(fā)執(zhí)行清除階段,正如名稱(chēng)所示,不執(zhí)行“stop-the-world”,并發(fā)實(shí)施操作。
正如我們們從GC日志看到的真實(shí)情況,事實(shí)上,替代兩次Full GC的僅僅一次Major GC清理Old space。
如果你考慮了基于jstat展示的數(shù)據(jù)的情況,你會(huì)做出正確結(jié)論。它正確展示出兩次因?yàn)樗谢顒?dòng)線(xiàn)程而進(jìn)行兩次“stop-the-world”,總共耗費(fèi)50ms。如果你想為了吞吐量嘗試優(yōu)化,那么你會(huì)被誤導(dǎo),僅僅在初始化標(biāo)記和最后重復(fù)標(biāo)記階段而進(jìn)行“stop-the-world”,the jstat輸出完全隱藏了并發(fā)工作。
結(jié)論
綜合情況來(lái)看,這是避免考慮項(xiàng)目中Minor, Major or Full GC的最好方式。反之,監(jiān)控你的應(yīng)用延遲或者吞吐量,將結(jié)果和GC事件聯(lián)系起來(lái)。連同這些事件一起,你額外需要相關(guān)信息,特別是GC事件強(qiáng)迫停止應(yīng)用線(xiàn)程和并發(fā)處理部分事件。
如果你對(duì)本次內(nèi)容感興趣,這是目前有效的實(shí)例章節(jié)Garbage Collection Handbook。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66313.html
摘要:原文出處這種垃圾收集器的官方名稱(chēng)是。使用收集器的名稱(chēng)。事件時(shí)長(zhǎng)記錄不同的類(lèi)型回收期間垃圾收集器線(xiàn)程消耗事件調(diào)用操作系統(tǒng)活著等待系統(tǒng)事件消耗時(shí)間應(yīng)用停頓的時(shí)鐘時(shí)間?,F(xiàn)在我們看一些一些任務(wù)的時(shí)間,垃圾收集器線(xiàn)程等待很長(zhǎng)時(shí)間。 原文出處:Concurrent Mark and Sweep 這種垃圾收集器的官方名稱(chēng)是Mostly Concurrent Mark and Sweep Garbag...
摘要:堆內(nèi)存使用分析,垃圾收集器日志解讀重要的東東在中,對(duì)象實(shí)例都是在堆上創(chuàng)建。機(jī)制是由提供,用來(lái)清理需要清除的對(duì)象,回收堆內(nèi)存。在中,是由一個(gè)被稱(chēng)為垃圾回收器的守護(hù)線(xiàn)程執(zhí)行的。 堆內(nèi)存使用分析,垃圾收集器 GC 日志解讀 重要的東東 在Java中,對(duì)象實(shí)例都是在堆上創(chuàng)建。一些類(lèi)信息,常量,靜態(tài)變量等存儲(chǔ)在方法區(qū)。堆和方法區(qū)都是線(xiàn)程共享的。 GC機(jī)制是由JVM提供,用來(lái)清理需要清除的對(duì)象,...
摘要:本人使用的是,以下涉及的默認(rèn)值均以該版本為準(zhǔn)。其中,新生代被細(xì)分為和兩個(gè)區(qū)域,這兩個(gè)區(qū)域分別被命名為和,以示區(qū)分。其中新生帶存放新生的對(duì)象或者年齡不大的對(duì)象,老年代則存放老年對(duì)象。 什么是垃圾回收機(jī)制 不定時(shí)去堆內(nèi)存中清理不可達(dá)對(duì)象。不可達(dá)的對(duì)象并不會(huì)馬上就會(huì)直接回收, 垃圾收集器在一個(gè)Java程序中的執(zhí)行是自動(dòng)的,不能強(qiáng)制執(zhí)行,即使程序員能明確地判斷出有一塊內(nèi)存已經(jīng)無(wú)用了,是應(yīng)該回收...
摘要:這個(gè)算法看似不錯(cuò)而且簡(jiǎn)單,不過(guò)存在這一個(gè)致命傷當(dāng)兩個(gè)對(duì)象互相引用的時(shí)候,就永遠(yuǎn)不會(huì)被回收于是引用計(jì)數(shù)算法就永遠(yuǎn)回收不了這兩個(gè)對(duì)象,下面介紹另一種算法。 前言 ? 如果要問(wèn)Java與其他編程語(yǔ)言最大的不同是什么,我第一個(gè)想到的一定就是Java所運(yùn)行的JVM所自帶的自動(dòng)垃圾回收機(jī)制,以下是我學(xué)習(xí)JVM垃圾回收機(jī)制整理的筆記,希望能對(duì)讀者有一些幫助。 哪些內(nèi)存需要回收?what? ? ...
摘要:如果開(kāi)啟,則每次后會(huì)重新計(jì)算和區(qū)的大小,計(jì)算依據(jù)是過(guò)程中統(tǒng)計(jì)的時(shí)間吞吐量?jī)?nèi)存占用量。應(yīng)用達(dá)到預(yù)期的吞吐量,即應(yīng)用正常運(yùn)行時(shí)間正常運(yùn)行時(shí)間耗時(shí)。理論上,增大內(nèi)存,可以降低的頻率,以此達(dá)到預(yù)期吞吐量。 轉(zhuǎn)載請(qǐng)注明原文鏈接:https://www.jianshu.com/p/741... 一、AdaptiveSizePolicy簡(jiǎn)介 AdaptiveSizePolicy(自適應(yīng)大小策略) ...
閱讀 664·2021-11-11 16:55
閱讀 2166·2021-11-11 16:55
閱讀 1958·2021-11-11 16:55
閱讀 2350·2021-10-25 09:46
閱讀 1614·2021-09-22 15:20
閱讀 2295·2021-09-10 10:51
閱讀 1712·2021-08-25 09:38
閱讀 2626·2019-08-30 12:48