一、背景
線(xiàn)上環(huán)境下麻昼,jvm經(jīng)常發(fā)生full gc奠支;運(yùn)維監(jiān)控方面,服務(wù)健康檢測(cè)不健康抚芦;用戶(hù)體驗(yàn)方面倍谜,經(jīng)常出現(xiàn)大量的慢接口調(diào)用。
經(jīng)觀察叉抡,這三者是伴隨發(fā)生的尔崔。起初,我們從慢接口入手褥民,看到接口中的慢主要是在訪(fǎng)問(wèn)數(shù)據(jù)存儲(chǔ)層的時(shí)候季春,但是去數(shù)據(jù)庫(kù)卻沒(méi)有看到任何的慢查詢(xún)?nèi)罩荆ò╩ongodb和redis);但是能解釋為什么服務(wù)不健康消返,服務(wù)假死了载弄,不再能夠消費(fèi)任何請(qǐng)求。
所以撵颊,我們就先解決導(dǎo)致接口慢的原因(gc)宇攻。
二、業(yè)務(wù)特點(diǎn)
業(yè)務(wù)上的接口 秦驯,慢大多數(shù)都是查詢(xún)類(lèi)的 尺碰,會(huì)生成大量jvm對(duì)象在堆內(nèi)存中挣棕。
先是在年輕代译隘,由young gc回收,如果年輕代的內(nèi)存不夠洛心,則會(huì)直接分配到年老代固耘。
年老代的內(nèi)存大小有限,要回收他們词身,就只有full gc了厅目。
當(dāng)然,在年輕代的對(duì)象法严,要想回收损敷,和對(duì)象的年齡也有關(guān)。
所以深啤,我們的初步思路是增大年輕代的內(nèi)存拗馒,讓對(duì)象盡可能在young gc就回收了。
目標(biāo)
- 年輕代的對(duì)象回收溯街,呈現(xiàn)鋸齒形诱桂。
- 最終是為了減少full gc
三洋丐、jdk8的默認(rèn)垃圾回收器ParallelGC
Parallel Scavenge + Parallel Old
- java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=67108864 -XX:MaxHeapSize=1073741824 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
實(shí)際運(yùn)行的jvm參數(shù)是
java -Xms2800m -Xmx2800m -XX:SurvivorRatio=18 -XX:MaxTenuringThreshold=15 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError -jar /opt/xx/xxx.jar
參考地址:
MaxTenuringThreshold 年齡大小,默認(rèn)15
SurvivorRatio 默認(rèn)8挥等,Eden占新生代的8/10友绝,F(xiàn)rom幸存區(qū)和To幸存區(qū)各占新生代的1/10。(它和-Xmn大小有關(guān))
四肝劲、jvm體系結(jié)構(gòu)
五迁客、目標(biāo)
1、降低 Minor GC 頻率
通常情況下辞槐,由于新生代空間較小哲泊,Eden 區(qū)很快被填滿(mǎn),就會(huì)導(dǎo)致頻繁 Minor GC催蝗,因此我們可以通過(guò)增大新生代空間來(lái)降低 Minor GC 的頻率切威。
可能你會(huì)有這樣的疑問(wèn),擴(kuò)容 Eden 區(qū)雖然可以減少 Minor GC 的次數(shù)丙号,但不會(huì)增加單次 Minor GC 的時(shí)間嗎先朦?
我們知道,單次 Minor GC 時(shí)間是由兩部分組成:T1(掃描新生代)和 T2(復(fù)制存活對(duì)象)犬缨。
假設(shè)一個(gè)對(duì)象在 Eden 區(qū)的存活時(shí)間為 500ms喳魏,Minor GC 的時(shí)間間隔是 300ms,那么正常情況下怀薛,Minor GC 的時(shí)間為:T1+T2刺彩。
當(dāng)我們?cè)龃笮律臻g,Minor GC 的時(shí)間間隔可能會(huì)擴(kuò)大到 600ms枝恋,此時(shí)一個(gè)存活 500ms 的對(duì)象就會(huì)在 Eden 區(qū)中被回收掉创倔,此時(shí)就不存在復(fù)制存活對(duì)象了,
所以再發(fā)生 Minor GC 的時(shí)間為:兩次掃描新生代焚碌,即 2T1畦攘。可見(jiàn)十电,擴(kuò)容后知押,Minor GC 時(shí)增加了 T1,但省去了 T2 的時(shí)間鹃骂。
通常在虛擬機(jī)中台盯,復(fù)制對(duì)象的成本要遠(yuǎn)高于掃描成本。如果在堆內(nèi)存中存在較多的長(zhǎng)期存活的對(duì)象畏线,此時(shí)增加年輕代空間静盅,反而會(huì)增加 Minor GC 的時(shí)間。
如果堆中的短期對(duì)象很多象踊,那么擴(kuò)容新生代温亲,單次 Minor GC 時(shí)間不會(huì)顯著增加棚壁。
因此,單次 Minor GC 時(shí)間更多取決于 GC 后存活對(duì)象的數(shù)量栈虚,而非 Eden 區(qū)的大小袖外。
-Xmn1500m, 之前的年輕代就500m~700m。
2魂务、降低 Full GC 的頻率
通常情況下曼验,由于堆內(nèi)存空間不足或老年代對(duì)象太多,會(huì)觸發(fā) Full GC粘姜,頻繁的 Full GC 會(huì)帶來(lái)上下文切換鬓照,增加系統(tǒng)的性能開(kāi)銷(xiāo)。
我們可以使用哪些方法來(lái)降低 Full GC 的頻率呢孤紧?
減少創(chuàng)建大對(duì)象:在平常的業(yè)務(wù)場(chǎng)景中豺裆,我們習(xí)慣一次性從數(shù)據(jù)庫(kù)中查詢(xún)出一個(gè)大對(duì)象用于 web 端顯示。 例如号显,我之前碰到過(guò)一個(gè)一次性查詢(xún)出 60 個(gè)字段的業(yè)務(wù)操作臭猜,這種大對(duì)象如果超過(guò)年輕代最大對(duì)象閾值,會(huì)被直接創(chuàng)建在老年代押蚤;
即使被創(chuàng)建在了年輕代蔑歌,由于年輕代的內(nèi)存空間有限,通過(guò) Minor GC 之后也會(huì)進(jìn)入到老年代揽碘。 這種大對(duì)象很容易產(chǎn)生較多的 Full
GC次屠。我們可以將這種大對(duì)象拆解出來(lái),首次只查詢(xún)一些比較重要的字段雳刺,如果還需要其它字段輔助查看劫灶,再通過(guò)第二次查詢(xún)顯示剩余的字段。
增大堆內(nèi)存空間:在堆內(nèi)存不足的情況下煞烫,增大堆內(nèi)存空間浑此,且設(shè)置初始化堆內(nèi)存為最大堆內(nèi)存累颂,也可以降低 Full GC 的頻率滞详。
把jvm堆內(nèi)存由2800m --> 3800m, 且兩者一樣大 -Xms3800m -Xmx3800m
3、垃圾回收器為CMS
-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSInitiatingOccupancyOnly
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
新生代使用ParNew紊馏,老年代使用CMS-XX:+CMSParallelRemarkEnabled
降低標(biāo)記停頓-XX:CMSInitiatingOccupancyFraction=92
參考:
六料饥、調(diào)整后的效果對(duì)比
1、full gc 頻率顯著減少
2朱监、慢接口不再劇增
3岸啡、年輕代內(nèi)存增大
-
調(diào)整前
-
調(diào)整后
年輕代的內(nèi)存呈現(xiàn)鋸齒形,說(shuō)明年輕代的對(duì)象得到了及時(shí)回收赫编。
4巡蘸、老年代的內(nèi)存增速顯著變慢
七奋隶、總結(jié)
1、AdaptiveSizePolicy
idea在配置啟動(dòng)參數(shù)-XX:SurvivorRatio時(shí)不生效的問(wèn)題悦荒,是因?yàn)镴DK 1.8 默認(rèn)使用 UseParallelGC 垃圾回收器唯欣,該垃圾回收器默認(rèn)啟動(dòng)了 AdaptiveSizePolicy(自適應(yīng)大小策略),會(huì)根據(jù)GC的情況自動(dòng)計(jì)算計(jì)算 Eden搬味、From 和 To 區(qū)的大芯城狻;要使-XX:SurvivorRatio生效碰纬,就需要關(guān)閉該策略 -XX:-UseAdaptiveSizePolicy萍聊。
2、使用CMS時(shí)悦析,會(huì)默認(rèn)停用AdaptiveSizePolicy開(kāi)關(guān)
/ # jinfo -flag UseAdaptiveSizePolicy 8
-XX:-UseAdaptiveSizePolicy
驗(yàn)證SurvivorRatio的設(shè)置是否生效
jinfo -flag SurvivorRatio 8
-XX:SurvivorRatio=18
驗(yàn)證是否啟用了CMS垃圾回收器
jinfo -flag UseConcMarkSweepGC 8
-XX:+UseConcMarkSweepGC