摘要:是一款基于并發(fā)使用標(biāo)記清除算法的垃圾回收算法,只針對(duì)老年代進(jìn)行垃圾回收。收集器工作時(shí),工作線程和用戶線程可以并發(fā)執(zhí)行,以達(dá)到降低時(shí)間的目的。并發(fā)清理清理垃圾對(duì)象,這個(gè)階段線程和用戶線程并發(fā)執(zhí)行。
背景
我們上線Java服務(wù)的時(shí)候需要對(duì)其配置一些JVM參數(shù),如堆空間大小、虛擬機(jī)棧大小、垃圾回收算法。對(duì)于年輕代和老年代我們可以配置不同的垃圾回收算法。在一些對(duì)rt要求很高的場(chǎng)景,服務(wù)不能有長時(shí)間的卡頓,CMS就可以運(yùn)用于此場(chǎng)景。
Concurrent Mark Sweep,是一款基于并發(fā)、使用標(biāo)記清除算法的垃圾回收算法,只針對(duì)老年代進(jìn)行垃圾回收。CMS收集器工作時(shí),GC工作線程和用戶線程可以并發(fā)執(zhí)行,以達(dá)到降低STW時(shí)間的目的。
開起VM選項(xiàng)-XX:+UseConcMarkSweepGC,表示對(duì)老年代的回收采用CMS。
前置知識(shí) STW首先,我們需要厘清一個(gè)概念,即只有標(biāo)記階段才需要STW。標(biāo)記完成以后,需要清除的對(duì)象已經(jīng)確定,無論此時(shí)是否產(chǎn)生新的垃圾,都不影響對(duì)這些對(duì)象的清理。也就是說,清除階段是可以設(shè)計(jì)成和用戶線程并發(fā)執(zhí)行的。
JVM在暫停的時(shí)候,需要選準(zhǔn)一個(gè)時(shí)機(jī),由于JVM系統(tǒng)運(yùn)行期間的復(fù)雜性,不可能做到隨時(shí)暫停,因此引入了安全點(diǎn)(safepoint)的概念:程序只有在運(yùn)行到安全點(diǎn)的時(shí)候,才可以暫停下來。HotSpot采用主動(dòng)中斷的方式,讓執(zhí)行線程在運(yùn)行期輪詢是否需要暫停的標(biāo)志,若需要?jiǎng)t中斷掛起。HotSpot使用了幾條短小精煉的匯編指令便可完成安全點(diǎn)輪詢以及觸發(fā)線程中斷,因此對(duì)系統(tǒng)性能的影響幾乎可以忽略不計(jì)。
可達(dá)性可達(dá)性是指,如果一個(gè)對(duì)象會(huì)被至少一個(gè)程序中的可達(dá)對(duì)象通過直接或間接的方式引用,則稱該對(duì)象是可達(dá)的。更詳細(xì)地說,一個(gè)對(duì)象滿足一下兩個(gè)條件之一,即被判定為可達(dá)的。
1.本身是根對(duì)象。根(root)是指由堆以外空間訪問的對(duì)象。JVM會(huì)將以下對(duì)象標(biāo)記為根:a.虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象;b.方法區(qū)中的類靜態(tài)屬性引用的對(duì)象;c.方法區(qū)中的常量引用的對(duì)象;d.本地方法棧中JNI的引用對(duì)象。
2.被一個(gè)可達(dá)的對(duì)象引用。
CMS的幾個(gè)階段CMS將可達(dá)性分析分解成兩個(gè)階段:a.僅掃描與根節(jié)點(diǎn)直接關(guān)聯(lián)的對(duì)象; b.繼續(xù)向下掃描完所有對(duì)象。因此,標(biāo)記階段也被拆分成兩個(gè)階段,即初始標(biāo)記和并發(fā)標(biāo)記。
CMS完整的收集過程如下:
初始標(biāo)記(init-mark):僅掃描與根節(jié)點(diǎn)直接關(guān)聯(lián)的對(duì)象并標(biāo)記,這個(gè)階段必須STW, 由于跟節(jié)點(diǎn)數(shù)量有限,所以這個(gè)過程非常短暫。
并發(fā)標(biāo)記(concurrent-marking):與用戶線程并發(fā)標(biāo)記。這個(gè)階段在初始標(biāo)記的基礎(chǔ)上繼續(xù)向下追溯標(biāo)記。在并發(fā)標(biāo)記階段,用戶線程和標(biāo)記線程并發(fā)執(zhí)行,所以用戶不會(huì)感受到停頓。
并發(fā)預(yù)清理(concurrent-precleaning):與用戶線程并發(fā)進(jìn)行。在并發(fā)標(biāo)記階段一些對(duì)象的引用已經(jīng)發(fā)生了變化,precleaning會(huì)發(fā)現(xiàn)這些引用關(guān)系的改變,并將存活的對(duì)象標(biāo)記。舉個(gè)例子:如果線程A有一個(gè)指向?qū)ο骕的引用,并將該引用傳遞給了線程B,CMS需要記錄下線程B持有了對(duì)象X,即使線程A已經(jīng)不存在了。precleaning是為了減少下一階段“重新標(biāo)記”的工作量,因?yàn)?b>remark階段會(huì)STW。
重新標(biāo)記(remark): remark階段會(huì)STW。如果應(yīng)用正在并發(fā)運(yùn)行且在不斷地改變對(duì)象引用,CMS則不能準(zhǔn)確地確定某個(gè)對(duì)象是否存活。所以CMS會(huì)在remark階段STW,從而獲取所有引用關(guān)系的改變。
并發(fā)清理(concurrent-sweeping):清理垃圾對(duì)象,這個(gè)階段GC線程和用戶線程并發(fā)執(zhí)行。
并發(fā)重置(concurrent-reset):重置CMS收集器的數(shù)據(jù)結(jié)構(gòu),做好下一次執(zhí)行GC任務(wù)的準(zhǔn)備工作。
線上Full GC分析線上某服務(wù)的老年代配置了CMS,但卻在gc.log發(fā)現(xiàn)連續(xù)Full GC的問題。JVM參數(shù)配置如下:
-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68
參數(shù)的意義是:在老年代到68%的時(shí)候,會(huì)觸發(fā)一次CMS GC,應(yīng)該是出現(xiàn)類似如下的日志:
T20:10:37.803+0800: 3246087.559: [CMS-concurrent-mark-start] T20:10:38.463+0800: 3246088.220: [CMS-concurrent-mark: 0.661/0.661 secs] [Times: user=3.17 sys=0.56, real=0.66 secs] T20:10:38.463+0800: 3246088.220: [CMS-concurrent-preclean-start] T20:10:38.552+0800: 3246088.309: [CMS-concurrent-preclean: 0.069/0.089 secs] [Times: user=0.14 sys=0.04, real=0.09 secs]_ T20:10:38.552+0800: 3246088.309: [CMS-concurrent-abortable-preclean-start]
但線上環(huán)境的日志卻出現(xiàn)如下的情況:
老年代配置了900M,但卻在只使用了50+M的時(shí)候觸發(fā)了Full GC,而且是在短暫的時(shí)間內(nèi)連續(xù)觸發(fā)。
配置了CMS卻觸發(fā)Full GC,有以下幾種可能:
大對(duì)象分配時(shí),年輕代不夠,直接晉升到老年代,老年代空間也不夠,觸發(fā) Full GC(老年代還剩800+M,顯然不可能)
內(nèi)存碎片導(dǎo)致(由于CMS是基于標(biāo)記清除算法的,所有會(huì)導(dǎo)致內(nèi)存碎片,但通過grep -i "cms" gc.log,JVM尚未觸發(fā)過CMS回收,所以也不存在內(nèi)存碎片的說法)
CMS GC失敗導(dǎo)致(從gc.log并未找到concurrent mode failure的記錄,排除)
jmap -histo(人為執(zhí)行該命令)
經(jīng)筆者回憶,在中午快12點(diǎn)的時(shí)候確實(shí)登錄過線上機(jī),執(zhí)行過jmap -histo:live命令,經(jīng)驗(yàn)證,手動(dòng)執(zhí)行jmap -histo:live,也確實(shí)會(huì)在gc.log出現(xiàn)觸發(fā) Full GC的現(xiàn)象,問題得到驗(yàn)證。
原文鏈接https://segmentfault.com/a/11...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/69650.html
摘要:虛擬機(jī)所處的區(qū)域,則表示它是屬于新生代收集器還是老年代收集器。虛擬機(jī)總共運(yùn)行了分鐘,其中垃圾收集花掉分鐘,那么吞吐量就是。收集器線程所占用的數(shù)量為。 本文主要從GC(垃圾回收)的角度試著對(duì)jvm中的內(nèi)存分配策略與相應(yīng)的垃圾收集器做一個(gè)介紹。 注:還是老規(guī)矩,本著能畫圖就不BB原則,盡量將各知識(shí)點(diǎn)通過思維導(dǎo)圖或者其他模型圖的方式進(jìn)行說明。文字僅記錄額外的思考與心得,以及其他特殊情況 內(nèi)存...
摘要:原文鏈接本篇是專家系列的第三篇。但是,請(qǐng)記住調(diào)優(yōu)是不得已時(shí)的選擇。縮短耗時(shí)的單次執(zhí)行與相比,耗時(shí)有較明顯的增加。創(chuàng)建文件過程中,進(jìn)程會(huì)中斷,因此不要在正常運(yùn)行時(shí)系統(tǒng)上做此操作。因此校驗(yàn)結(jié)果并根據(jù)具體的服務(wù)需要,決定是否要進(jìn)行調(diào)優(yōu)。 原文鏈接:http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collecti...
摘要:直接顯示了一個(gè)疑似內(nèi)存泄漏的問題。然后分析文件給出的信息,發(fā)現(xiàn)一個(gè)叫的類。文件里面說的內(nèi)存泄漏的大概的意思就是說,這個(gè)類里面的存放的東西太多了,爆掉了。修改了代碼將調(diào)用的地方改成了單例。修改完線上跑了一段日子,后來也沒有出現(xiàn)過這樣的問題。 問題描述: ????早上去公司上班,突然就郵件一直報(bào)警,接口報(bào)異常,然后去查服務(wù)器的運(yùn)行情況,發(fā)現(xiàn)java的cpu爆了.接著就開始排查問題 問題解決...
摘要:深入理解虛擬機(jī)高級(jí)特性與最佳實(shí)踐第二版讀書筆記與常見面試題總結(jié)上篇文章傳送門深入理解虛擬機(jī)之內(nèi)存區(qū)域本節(jié)常見面試題推薦帶著問題閱讀,問題答案在文中都有提到如何判斷對(duì)象是否死亡兩種方法。虛引用主要用來跟蹤對(duì)象被垃圾回收的活動(dòng)。 《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(第二版》讀書筆記與常見面試題總結(jié) 上篇文章傳送門: 深入理解虛擬機(jī)之Java內(nèi)存區(qū)域 本節(jié)常見面試題(推薦帶著...
閱讀 1785·2021-11-11 11:02
閱讀 1694·2021-09-22 15:55
閱讀 2493·2021-09-22 15:18
閱讀 3493·2019-08-29 11:26
閱讀 3752·2019-08-26 13:43
閱讀 2652·2019-08-26 13:32
閱讀 907·2019-08-26 10:55
閱讀 971·2019-08-26 10:27