JVM調(diào)優(yōu)相關(guān)

本文分析基于Serial贸典,cms考赛,parnew一罩,等經(jīng)典分代垃圾收集器月趟。
對JVM內(nèi)存的系統(tǒng)級的調(diào)優(yōu)主要的目的是減少GC的頻率和Full GC的次數(shù)灯蝴。導(dǎo)致Full GC的原因一般是老年代、元空間 不足孝宗。

先了解對象的空間分配機制绽乔,也是調(diào)優(yōu)的基礎(chǔ)

1. 對象優(yōu)先在Eden分配

Eden 內(nèi)存不夠用會出發(fā)Minor GC
可能會有99%以上的被回收掉,剩余存活的被挪到為空的那塊survivor區(qū)碳褒,下一次eden區(qū)滿了后又會觸發(fā)minor gc折砸,把eden區(qū)和survivor區(qū)垃圾回收,把存活的對象一次性挪到另外一塊為空的survivor區(qū)(survivor存不下會直接存入老年代)沙峻。因為新生代的對象都是朝生夕死的睦授,存活時間很短,所以JVM默認的8:1:1的比例是很合適的摔寨,讓eden區(qū)盡量的大去枷,survivor區(qū)夠用即可。

2. 長期存活的對象進入老年代

對象頭中存儲對象年齡是复,
對象在Eden誕生删顶,經(jīng)過第一次MinorGC后依然存活,且能被survivor 容納淑廊,會被移動到survivor 并且年齡為1逗余。對象在survivor中每熬過一次MinorGC年齡就加1.
到達一定年齡(默認15,cms默認6)進入老年代季惩。不能被survivor容納录粱,直接入老年代。
如果 -XX:MaxTenuringThreshold=1画拾,則在第二次MinorGC時啥繁,進入老年代

3. 大對象直接進入老年代配置

參數(shù) -XX:pretenureSizeThreshold=1000 (單位是字節(jié)) 控制對象空間大于指定大小 直接進入老年代,需要在新生代使用對應(yīng)的垃圾收集器青抛。
以下兩種都可以支持旗闽。
-XX:+UseSerialGc
-XX:+UseParNew
這樣設(shè)置可避免大對象在Eden和兩個s區(qū)來回復(fù)制,產(chǎn)生大量的內(nèi)存復(fù)制操作蜜另。

4. 動態(tài)對象年齡判定

survivor 中 相同年齡的對象總和适室,大于survivor空間的一半,大于等于該年齡的對象可以直接進入老年代蚕钦。無需等待到閾值年齡亭病。

5. 空間分配擔保

發(fā)生MinorGC 之前,虛擬機需要先檢查老年代最大可用連續(xù)空間嘶居,是否大于新生代所有對象總空間。如果大于,執(zhí)行MinorGC, 否則看是否設(shè)置了允許擔保邮屁。
如果允許擔保整袁,則判斷老年代最大可用連續(xù)空間是否大于 以往晉升到老年代對象的平均值, 如果大于佑吝,進行MinorGC, 如果小于坐昙,或者未設(shè)置擔保,先進行Full Gc.
擔保內(nèi)容:Minor Gc之后大量對象依然存活芋忿,需要把無法存入survivor的對象直接送入老年代炸客。

調(diào)優(yōu)步驟

1. jinfo 查詢 jvm參數(shù),明確各區(qū)域內(nèi)存空間大小

jinfo -flags pid

2. 明確年輕代對象增長的速率--》確定Eden 多久被放滿

可以執(zhí)行命令 jstat -gc pid 1000 10 (每隔1秒執(zhí)行1次命令戈钢,共執(zhí)行10次痹仙,打印堆、元空間的容量殉了、已用空間开仰,gc耗時等信息),通過觀察EU(eden區(qū)的已使用)來估算每秒eden大概新增多少對象薪铜,如果系統(tǒng)負載不高众弓,可以把頻率1秒換成1分鐘,甚至10分鐘來觀察整體情況隔箍。注意谓娃,一般系統(tǒng)可能有高峰期和日常期,所以需要在不同的時間分別估算不同情況下對象增長速率蜒滩。

假設(shè) 每秒5M傻粘, 100s 放滿Eden 區(qū),那么100s 進行一次youngGC帮掉,如需放大年輕代gc周期弦悉,可以適當增大年輕代。并且考慮高峰期時蟆炊,業(yè)務(wù)量情況稽莉。

3. 明確Young GC的觸發(fā)頻率和每次耗時

知道年輕代對象增長速率,就能推根據(jù)eden區(qū)的大小推算出Young GC大概多久觸發(fā)一次涩搓,Young GC的平均耗時可以通過 YGCT/YGC大致計算得出污秆,根據(jù)結(jié)果大概就能知道系統(tǒng)大概多久會因為Young GC的執(zhí)行而卡頓多久。

4. 明確老年代對象增長速率

之前已經(jīng)大概知道Young GC的頻率昧甘,假設(shè)是每5分鐘一次良拼,那么可以執(zhí)行命令 jstat -gc pid 300000 10 ,300000 即5分鐘的毫秒數(shù)充边,觀察每次結(jié)果eden庸推,survivor和老年代使用的變化情況常侦,在每次gc后eden區(qū)使用一般會大幅減少,survivor和老年代都有可能增長贬媒,這些增長的對象就是每次Young GC后存活的對象聋亡,同時還可以看出每次Young GC后進去老年代大概多少對象,從而可以推算出老年代對象增長速率际乘。
需要考慮業(yè)務(wù)場景高峰期時坡倔,對象增長率突增。

5. Full GC的觸發(fā)頻率和每次耗時

知道了老年代對象的增長速率就可以推算出Full GC的觸發(fā)頻率了脖含,F(xiàn)ull GC的每次耗時可以用公式 FGCT/FGC 計算得出罪塔。根據(jù)業(yè)務(wù)需要調(diào)整老年代大小⊙控制full gc 頻率征堪。

6. 也根據(jù)業(yè)務(wù)場景分析每秒產(chǎn)生對象大小

假設(shè)每秒 500 個訂單的系統(tǒng),每個訂單對象 大概占用空間多大(根據(jù)字段屬性大致計算)港柜。假設(shè)每個對象1kb, 每秒 0.5M请契, 由于系統(tǒng)還有 查詢服務(wù)等其他對象。預(yù)估每秒對象占用空間 0.5 * 10 = 5M夏醉,如果 設(shè)置新生代 500M,比例 8:1:1爽锥,那么Eden 400M,80s Eden 放滿畔柔,進行young GC氯夷。

最終目標

朝生夕死的對象,盡可能在 young GC 后回收靶擦,存活較久的對象盡早進入老年代腮考。降低Full GC 、young GC 頻率, 維持穩(wěn)定的gc頻率玄捕。根據(jù)GC 耗時踩蔚,業(yè)務(wù)系統(tǒng)允許停頓時間,最終確定 堆空間大小和布局比例枚粘,進行驗證馅闽,反復(fù)調(diào)整。

特殊情況

如果fullgc 頻率較高馍迄,需要考慮以下幾種情況:

  1. 是否觸發(fā)了空間擔保機制 --- 設(shè)置允許擔保(默認允許)
  2. 是否因為survivor 太小導(dǎo)致對象過早進入老年代 --- 需要調(diào)整 增大 survivor
  3. 是否在代碼中調(diào)用GC -- 通過參數(shù)禁止
  4. 元空間不足 -- 會自動擴展福也,但還是設(shè)置合適較好。

如果young GC 頻繁攀圈,需要調(diào)整增大新生代暴凑,一般設(shè)置固定大小,不允許擴展赘来。具體大小根據(jù)業(yè)務(wù)量計算现喳。

嘗試之后GC還是很頻繁凯傲,考慮使用jmap堆中哪些對象占用空間較大,配合top 拿穴、jstack查看哪個線程在頻繁創(chuàng)建該對象泣洞。根據(jù)代碼分析是否存在問題.
jmap -histo [pid] 查看內(nèi)存信息忧风,實例個數(shù)以及占用內(nèi)存大小
配合top -Hp pid 查詢內(nèi)存占用較高的線程默色,在使用jstack 命令

1,使用命令top -p <pid> 狮腿,顯示你的java進程的內(nèi)存情況腿宰,pid是你的java進程號,比如19663
2缘厢,按H吃度,獲取每個線程的內(nèi)存情況
3,找到內(nèi)存和cpu占用最高的線程tid贴硫,比如19664
4椿每,19664轉(zhuǎn)為十六進制得到 0x4cd0,此為線程id的十六進制表示
5英遭,執(zhí)行 jstack 19663|grep -A 10 4cd0间护,得到線程堆棧信息中 4cd0 這個線程所在行的后面10行,從堆棧中可以發(fā)現(xiàn)
6挖诸,查看對應(yīng)的堆棧信息找出可能存在問題的代碼

安全點導(dǎo)致的長時間停頓

根據(jù)gc日志觀察用戶線程停頓耗時汁尺,和垃圾收集耗時。差別較大時多律,可能存在安全點超時痴突。
gc需要所有用戶線程到達安全點才能開始。
代碼中出現(xiàn)的循環(huán)可能會導(dǎo)致安全點超時狼荞。

循環(huán)中的變量如果是int,jvm認為是可數(shù)循環(huán)辽装,可能不會在循還末尾設(shè)置安全點。中間如果存在耗時操作則會一直等待相味∈盎可以修改為long 型,jvm判定為不可數(shù)循環(huán)攻走。會在每次循環(huán)末尾設(shè)置安全點殷勘。也可以設(shè)置參數(shù)-XX:+UseCountedLoopSafepoints 強制可數(shù)循環(huán)中也防止安全點。這個參數(shù) jdk1.8部分版本存在bug需要注意昔搂。
設(shè)置虛擬機安全點等待時間玲销。超時2000ms后會自動打印線程名稱 方便問題排查。
-XX:+SafepointTimeout
-XX:SafepointTimeoutDelay=2000

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摘符,一起剝皮案震驚了整個濱河市贤斜,隨后出現(xiàn)的幾起案子策吠,更是在濱河造成了極大的恐慌,老刑警劉巖瘩绒,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猴抹,死亡現(xiàn)場離奇詭異,居然都是意外死亡锁荔,警方通過查閱死者的電腦和手機蟀给,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阳堕,“玉大人跋理,你說我怎么就攤上這事√褡埽” “怎么了前普?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壹堰。 經(jīng)常有香客問我拭卿,道長,這世上最難降的妖魔是什么贱纠? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任峻厚,我火速辦了婚禮,結(jié)果婚禮上并巍,老公的妹妹穿的比我還像新娘目木。我一直安慰自己,他們只是感情好懊渡,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布刽射。 她就那樣靜靜地躺著,像睡著了一般剃执。 火紅的嫁衣襯著肌膚如雪誓禁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天肾档,我揣著相機與錄音摹恰,去河邊找鬼。 笑死怒见,一個胖子當著我的面吹牛俗慈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遣耍,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼闺阱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了舵变?” 一聲冷哼從身側(cè)響起酣溃,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瘦穆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赊豌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扛或,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年碘饼,在試婚紗的時候發(fā)現(xiàn)自己被綠了熙兔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡派昧,死狀恐怖黔姜,靈堂內(nèi)的尸體忽然破棺而出拢切,到底是詐尸還是另有隱情蒂萎,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布淮椰,位于F島的核電站五慈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏主穗。R本人自食惡果不足惜泻拦,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忽媒。 院中可真熱鬧争拐,春花似錦、人聲如沸晦雨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闹瞧。三九已至绑雄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奥邮,已是汗流浹背万牺。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洽腺,地道東北人脚粟。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像蘸朋,于是被迫代替她去往敵國和親核无。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359