如何進行GC調(diào)優(yōu)

一、工具篇

要對我們的系統(tǒng)進行調(diào)優(yōu)命迈,首先需要知道我們的系統(tǒng)目前是什么樣子的,存在什么問題火的,jvm內(nèi)存是什么樣子壶愤,設(shè)定的jvm參數(shù)是什么樣子,用的垃圾收集器是什么馏鹤,只有知道這些信息征椒,才能進行下一步調(diào)優(yōu),所以湃累,調(diào)優(yōu)第一步勃救,首先查看目前系統(tǒng)的情況,下面是幾個常用的工具

1治力、jmp命令

命令: jmap -histo 7800(進程號蒙秒,根據(jù)jps查看當(dāng)前系統(tǒng)進程號)>./log.txt (將內(nèi)存信息輸入到當(dāng)前目錄下txt文件)
文件如圖:


image.png

從這里面我們可以知道,在我們的系統(tǒng)中宵统,哪些對象實例是最多的税肪,占的內(nèi)存最大,后面我們進行調(diào)優(yōu)很有可能就是基于這些對象的特點進行調(diào)優(yōu)

2、內(nèi)存溢出生成當(dāng)時快照

‐XX:+HeapDumpOnOutOfMemoryError ‐XX:HeapDumpPath=D:\jvm.dump
這個命令是我們系統(tǒng)的黑匣子(對比飛機上的黑瞎子)益兄,它的作用是在系統(tǒng)oom發(fā)生得那一刻锻梳,記錄當(dāng)時系統(tǒng)得內(nèi)存信息,對象信息净捅,新生代老年代分配情況等等一系列信息疑枯,并輸出到指定文件,我們依靠dump文件導(dǎo)入到一些可視化工具蛔六,進而分析什么原因?qū)е碌胦om荆永。

3、Jstat命令

jstat -gc pid 最常用国章,可以評估程序內(nèi)存使用及GC壓力整體情況
如圖


image.png

如圖
jstat -gc pid 1000 10 (輸出10次具钥,每次間隔1秒),這個可以很清晰得看到新生代液兽,老年代骂删,元空間的大小以及使用情況,能讓我們更好的的分析GC整體壓力以及性能瓶頸

4四啰、Jinfo 查看系統(tǒng)參數(shù)命令

jinfo -flags 進程id (查看運行中都jvm系統(tǒng)參數(shù))


image.png

jinfo -sysprops 進程id 查看java系統(tǒng)參數(shù)


image.png

5宁玫、Arthas

這個是阿里開源的一個非常好用的在線診斷工具 ,他的功能非常強大柑晒,我們常用的命令有:
(1) dashboard 可以查看整個進程的運行情況欧瘪,線程、內(nèi)存匙赞、GC佛掖、運行環(huán)境信息
(2) thread 可以查看線程詳細情況
(3) thread加上線程ID 可以查看線程堆棧
(4) thread -b 可以查看線程死鎖
(5) jad加類的全名 可以反編譯,這樣可以方便我們查看線上代碼是否是正確的版本
這里我們只是簡單的羅列了一些常用的命令 在線文檔 :https://arthas.aliyun.com/doc/ 具體我們可以參考文檔使用涌庭,其實筆者所在公司芥被,arthas作為基礎(chǔ)鏡像打入到了我們docker鏡像構(gòu)建中,所以我們每個容器都會自帶arthas,很方便對容器進行在線調(diào)試診斷脾猛,有興趣的同學(xué)不妨試試撕彤。

二鱼鸠、應(yīng)用篇

當(dāng)有了工具之后猛拴,我們就可以對系統(tǒng)進行評估,首先我們需要了解我們的服務(wù)器配置蚀狰,以及設(shè)定的java內(nèi)存大小愉昆,還有知道我們的系統(tǒng)采用的是什么來及收集器以及相關(guān)的參數(shù)配置,已筆者所在公司為例麻蹋,大部分系統(tǒng)都是用的cms垃圾收集器跛溉,這里我們回顧一下垃圾收集的整體過程

CMS整體流程圖

image.png

幾個階段:

1、初始標記:暫停所有的其他線程(STW),并記錄下gc roots直接能引用的對象芳室,速度很快专肪。
2、并發(fā)標記 基于初始標記的對象堪侯,繼續(xù)向下延展標記嚎尤,應(yīng)用線程不會停,過程比較長伍宦,由于應(yīng)用線程不停芽死,已經(jīng)標記的對象狀態(tài)可能發(fā)生改變
3、重新標記 重新標記階段就是為了修正并發(fā)標記期間因為用戶程序繼續(xù)運行而導(dǎo)致標記產(chǎn)生變動的那一部分對象的標記記錄次洼,比初始標記長关贵,但遠遠沒有并發(fā)標記時間長。應(yīng)用線此階段暫停
4卖毁、并發(fā)清理 基于之前的標記清理垃圾對象 揖曾,應(yīng)用線程不暫停
5、并發(fā)重置 清理對象的標記 势篡,應(yīng)用線程不暫停

同手我們還要了解所用垃圾收集器的核心參數(shù)設(shè)定翩肌,因為,我們調(diào)優(yōu)很有可能涉及到垃圾器的調(diào)優(yōu)禁悠,主要就是對垃圾收集器的核心參數(shù)修改已cms為例

1念祭、-XX:+UseConcMarkSweepGC:啟用cms
2、-XX:ConcGCThreads:并發(fā)的GC線程數(shù)
3碍侦、-XX:+CMSScavengeBeforeRemark:在CMS GC前啟動一次minor gc粱坤,目的在于減少老年代對年輕代的引 用,降低CMS GC的標記階段時的開銷瓷产,一般CMS的GC耗時 80%都在標記階段
4站玄、.-XX:+CMSParallellnitialMarkEnabled:表示在初始標記的時候多線程執(zhí)行,縮短STW
5濒旦、-XX:+CMSParallelRemarkEnabled:在重新標記的時候多線程執(zhí)行株旷,縮短STW;
6、-XX:CMSFullGCsBeforeCompaction:多少次FullGC之后壓縮一次尔邓,默認是0晾剖,代表每次FullGC后都會壓縮一 次
7、-XX:+CMSScavengeBeforeRemark:在CMS GC前啟動一次minor gc梯嗽,目的在于減少老年代對年輕代的引 用齿尽,降低CMS GC的標記階段時的開銷,一般CMS的GC耗時 80%都在標記階段
那么我們熟悉了系統(tǒng)的內(nèi)存信息以及垃圾收集器之后還需要哪些信息灯节?

JVM運行情況預(yù)估

1循头、用 jstat gc -pid 命令可以計算出如下一些關(guān)鍵數(shù)據(jù)绵估,有了這些數(shù)據(jù)就可以采用之前介紹過的優(yōu)化思路,先給自己的系統(tǒng)設(shè)置一些初始性的JVM參數(shù)卡骂,比如堆內(nèi)存大小国裳,年輕代大小,Eden和Survivor的比例全跨,老年代的大小躏救,大對象的閾值,大齡對象進入老年代的閾值等螟蒸。
2盒使、年輕代對象增長的速率 可以執(zhí)行命令 jstat -gc pid 1000 10 (每隔1秒執(zhí)行1次命令,共執(zhí)行10次)七嫌,通過觀察EU(eden區(qū)的使用)來估算每秒eden大概新增多少對象少办,如果系統(tǒng)負載不高,可以把頻率1秒換成1分鐘诵原,甚至10分鐘來觀察整體情況英妓。注意,一般系統(tǒng)可能有高峰期和日常期绍赛,所以需要在不同的時間分別估算不同情況下對象增長速率蔓纠。
3、Young GC的觸發(fā)頻率和每次耗時 知道年輕代對象增長速率我們就能推根據(jù)eden區(qū)的大小推算出Young GC大概多久觸發(fā)一次吗蚌,Young GC的平均耗時可以通過 YGCT/YGC公式算出腿倚,根據(jù)結(jié)果我們大概就能知道系統(tǒng)大概多久會因為Young GC的執(zhí)行而卡頓多久。
4蚯妇、每次Young GC后有多少對象存活和進入老年代 這個因為之前已經(jīng)大概知道Young GC的頻率敷燎,假設(shè)是每5分鐘一次,那么可以執(zhí)行命令 jstat -gc pid 300000 10 箩言,觀察每次結(jié)果eden硬贯,survivor和老年代使用的變化情況,在每次gc后eden區(qū)使用一般會大幅減少陨收,survivor和老年代都有可能增長饭豹,這些增長的對象就是每次Young GC后存活的對象,同時還可以看出每次Young GC后進去老年代大概多少對象务漩,從而可以推算出老年代對象增長速率拄衰。
5、Full GC的觸發(fā)頻率和每次耗時 知道了老年代對象的增長速率就可以推算出Full GC的觸發(fā)頻率了,F(xiàn)ull GC的每次耗時可以用公式 FGCT/FGC 計算得出谎势。
優(yōu)化思路其實簡單來說就是盡量讓每次Young GC后的存活對象小于Survivor區(qū)域的50%,都留存在年輕代里。盡量別讓對象進入老年代响逢。盡量減少Full GC的頻率旗唁,避免頻繁Full GC對JVM性能的影響。

觸發(fā)的full gc的幾個條件

1、老年代空間不足:新生代如果容量不足會將對象放到老年代源葫,老年代空間不足是會觸發(fā)full gc,通過-Xmn設(shè)置新生代大小,也可以通過-XX:NewRatio=n設(shè)置比例砖瞧,默認值是2息堂,老年代:新生代=》2:1
2、永久代空間不足:永久代在jdk7是存放在堆中的块促,可以通過-XX:PermSize=n和XX:MaxPermSize=n設(shè)置大荣堰。在jdk8中叫做元空間,使用的是計算機的本地內(nèi)存通過-XX:MaxMetaspaceSize=n設(shè)置大小竭翠,如果不設(shè)置振坚,默認最大內(nèi)存大小是計算機的本地內(nèi)存,由于運行時常量池在方法區(qū)中斋扰,而永久代又是方法區(qū)的實現(xiàn)渡八,所以運行時常量池隨著jdk8也移動到了本地內(nèi)存,但是無論是jdk7還是jdk8传货,字符串常量池還是在堆中屎鳍,字符串常量的創(chuàng)建是需要消耗堆內(nèi)存的
3、CMS 產(chǎn)生碎片過多已經(jīng)扛不住壓力了就會調(diào)用full gc進行整合:可以通過-XX:CMSFullGCsBeforeCompaction=n設(shè)置要執(zhí)行多少次full GC才會做壓縮问裕。默認是0逮壁,也就是每次full gc時就會對空間碎片進行整理,在默認配置下如果碎片過多CMS GC頂不住了粮宛,就要轉(zhuǎn)入full GC的時候都會做壓縮貌踏。(如果Full GC比較頻繁,那么就不能每次都整理內(nèi)存空間窟勃,不然積少成多祖乳,停頓的時間也是很可觀的,此時就要調(diào)大該參數(shù)秉氧,讓CMS在經(jīng)過多次Full GC后再對內(nèi)存空間進行壓縮整理,而如果Full GC發(fā)生的不頻繁眷昆,間隔時間較長,就可以設(shè)置成每次Full GC后都會對內(nèi)存空間進行壓縮整理汁咏,影響也不大亚斋。)
4、CMS GC時出現(xiàn)了promotion failed和concurrent mode failure:
(1)promotion failed意思是晉升失敗是由于新生代把一些對象往老年代扔攘滩,然后老年代空間不足則拋出“promotion failed”帅刊,觸發(fā)full gc,可能的原因是:Survivor空間過小或者老年代空間小或者碎片多漂问,或者兩者同時發(fā)生2赖瞒、concurrent mode failure是CMS設(shè)置啟動的老年代內(nèi)存占比閾值過高女揭,所以導(dǎo)致系統(tǒng)無法預(yù)留足夠的空間滿足程序需求,就會出現(xiàn)concurrent mode failure栏饮,啟動擔(dān)保機制吧兔,
5、老年代增長過快觸發(fā)full gc進行清理袍嬉,解決方法是降低觸發(fā)CMS的閥值境蔼,使用-XX:CMSInitiatingOccupancyFraction調(diào)低閾值,默認值是68伺通,可以調(diào)到50
6箍土、統(tǒng)計得到新生代minor gc時晉升到老年代的平均大小大于老生代剩余空間:
原因有幾個:1、代碼問題大量大對象直接進入老年代 2罐监、老年代空間不足涮帘,通過-XX:NewRatio=n可以調(diào)整老年代和年輕的堆比例
7、代碼直接調(diào)用System.gc()會建議系統(tǒng)調(diào)用full gc:在GC日志中會顯示為[Full GC(System),可以開啟-XX:-DisableExplicitGC禁止此類full gc

三笑诅、對比篇

正常來說调缨,對jvm的優(yōu)化,并不是立桿見影的吆你,甚至一次調(diào)整并沒有效果弦叶,一般來說,如果我們的系統(tǒng)是分布式集群環(huán)境妇多,同一系統(tǒng)有多臺服務(wù)的話可以現(xiàn)在一兩臺機器上做調(diào)優(yōu)設(shè)定伤哺,基于調(diào)整過的服務(wù)容器運行情況和未調(diào)整過的容器情況做的對比分析。通過一段時間的對比分析來確定有沒有效果者祖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末立莉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子七问,更是在濱河造成了極大的恐慌蜓耻,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件械巡,死亡現(xiàn)場離奇詭異刹淌,居然都是意外死亡,警方通過查閱死者的電腦和手機讥耗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門有勾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人古程,你說我怎么就攤上這事蔼卡。” “怎么了挣磨?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵雇逞,是天一觀的道長荤懂。 經(jīng)常有香客問我,道長喝峦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任呜达,我火速辦了婚禮谣蠢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘查近。我一直安慰自己眉踱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布霜威。 她就那樣靜靜地躺著谈喳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戈泼。 梳的紋絲不亂的頭發(fā)上婿禽,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機與錄音大猛,去河邊找鬼扭倾。 笑死,一個胖子當(dāng)著我的面吹牛挽绩,可吹牛的內(nèi)容都是我干的膛壹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼唉堪,長吁一口氣:“原來是場噩夢啊……” “哼模聋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唠亚,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤链方,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后灶搜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侄柔,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年占调,在試婚紗的時候發(fā)現(xiàn)自己被綠了暂题。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡究珊,死狀恐怖薪者,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剿涮,我是刑警寧澤言津,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布攻人,位于F島的核電站,受9級特大地震影響悬槽,放射性物質(zhì)發(fā)生泄漏怀吻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一初婆、第九天 我趴在偏房一處隱蔽的房頂上張望蓬坡。 院中可真熱鬧,春花似錦磅叛、人聲如沸屑咳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兆龙。三九已至,卻和暖如春敲董,著一層夾襖步出監(jiān)牢的瞬間紫皇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工腋寨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坝橡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓精置,卻偏偏與公主長得像计寇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子脂倦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容