問(wèn)題:
新上線一個(gè)java服務(wù),或者是RPC或者是WEB站點(diǎn)搬设, 內(nèi)存的設(shè)置該怎么設(shè)置呢穴店?設(shè)置成多大比較合適,既不浪費(fèi)內(nèi)存拿穴,又不影響性能呢泣洞?
分析:
依據(jù)的原則是根據(jù)Java Performance里面的推薦公式來(lái)進(jìn)行設(shè)置。
具體來(lái)講:
Java整個(gè)堆大小設(shè)置默色,Xmx 和 Xms設(shè)置為老年代存活對(duì)象的3-4倍球凰,即FullGC之后的老年代內(nèi)存占用的3-4倍
永久代 PermSize和MaxPermSize設(shè)置為老年代存活對(duì)象的1.2-1.5倍。
年輕代Xmn的設(shè)置為老年代存活對(duì)象的1-1.5倍腿宰。
老年代的內(nèi)存大小設(shè)置為老年代存活對(duì)象的2-3倍呕诉。
BTW:
1、Sun官方建議年輕代的大小為整個(gè)堆的3/8左右吃度, 所以按照上述設(shè)置的方式甩挫,基本符合Sun的建議。
2规肴、堆大小=年輕代大小+年老代大小捶闸, 即xmx=xmn+老年代大小 。 Permsize不影響堆大小拖刃。
3删壮、為什么要按照上面的來(lái)進(jìn)行設(shè)置呢? 沒(méi)有具體的說(shuō)明兑牡,但應(yīng)該是根據(jù)多種調(diào)優(yōu)之后得出的一個(gè)結(jié)論央碟。
如何確認(rèn)老年代存活對(duì)象大小均函?
方式1(推薦/比較穩(wěn)妥):
JVM參數(shù)中添加GC日志亿虽,GC日志中會(huì)記錄每次FullGC之后各代的內(nèi)存大小,觀察老年代GC之后的空間大小苞也÷迕悖可觀察一段時(shí)間內(nèi)(比如2天)的FullGC之后的內(nèi)存情況,根據(jù)多次的FullGC之后的老年代的空間大小數(shù)據(jù)來(lái)預(yù)估FullGC之后老年代的存活對(duì)象大腥绯佟(可根據(jù)多次FullGC之后的內(nèi)存大小取平均值)
方式2:(強(qiáng)制觸發(fā)FullGC, 會(huì)影響線上服務(wù)收毫,慎用)
方式1的方式比較可行攻走,但需要更改JVM參數(shù),并分析日志此再。同時(shí)昔搂,在使用CMS回收器的時(shí)候,有可能不能觸發(fā)FullGC(只發(fā)生CMS GC)输拇,所以日志中并沒(méi)有記錄FullGC的日志摘符。在分析的時(shí)候就比較難處理。
BTW:使用jstat -gcutil工具來(lái)看FullGC的時(shí)候策吠, CMS GC是會(huì)造成2次的FullGC次數(shù)增加逛裤。 具體可參見之前寫的一篇關(guān)于jstat使用的文章
所以,有時(shí)候需要強(qiáng)制觸發(fā)一次FullGC奴曙,來(lái)觀察FullGC之后的老年代存活對(duì)象大小别凹。
注:強(qiáng)制觸發(fā)FullGC,會(huì)造成線上服務(wù)停頓(STW)洽糟,要謹(jǐn)慎炉菲,建議的操作方式為,在強(qiáng)制FullGC前先把服務(wù)節(jié)點(diǎn)摘除坤溃,F(xiàn)ullGC之后再將服務(wù)掛回可用節(jié)點(diǎn)拍霜,對(duì)外提供服務(wù)
在不同時(shí)間段觸發(fā)FullGC,根據(jù)多次FullGC之后的老年代內(nèi)存情況來(lái)預(yù)估FullGC之后的老年代存活對(duì)象大小
如何觸發(fā)FullGC 薪介?
使用jmap工具可觸發(fā)FullGC
jmap -dump:live,format=b,file=heap.bin <pid> 將當(dāng)前的存活對(duì)象dump到文件祠饺,此時(shí)會(huì)觸發(fā)FullGC
jmap -histo:live <pid> 打印每個(gè)class的實(shí)例數(shù)目,內(nèi)存占用,類全名信息.live子參數(shù)加上后,只統(tǒng)計(jì)活的對(duì)象數(shù)量. 此時(shí)會(huì)觸發(fā)FullGC
具體操作實(shí)例:
以我司的一個(gè)RPC服務(wù)為例。
BTW:剛上線的新服務(wù)汁政,不知道該設(shè)置多大的內(nèi)存的時(shí)候道偷,可以先多設(shè)置一點(diǎn)內(nèi)存,然后根據(jù)GC之后的情況來(lái)進(jìn)行分析记劈。
初始JVM內(nèi)存參數(shù)設(shè)置為: Xmx=2G Xms=2G xmn=1G
使用jstat 查看當(dāng)前的GC情況勺鸦。如下圖:
YGC平均耗時(shí): 173.825s/15799=11ms
FGC平均耗時(shí):0.817s/41=19.9ms
平均大約10-20s會(huì)產(chǎn)生一次YGC
看起來(lái)似乎不錯(cuò),YGC觸發(fā)的頻率不高目木,F(xiàn)GC的耗時(shí)也不高换途,但這樣的內(nèi)存設(shè)置是不是有些浪費(fèi)呢?
為了快速看數(shù)據(jù)刽射,我們使用了方式2军拟,產(chǎn)生了幾次FullGC,F(xiàn)ullGC之后誓禁,使用的jmap -heap 來(lái)看的當(dāng)前的堆內(nèi)存情況(也可以根據(jù)GC日志來(lái)看)
heap情況如下圖:(命令 : jmap -heap <pid>)
上圖中的concurrent mark-sweep generation即為老年代的內(nèi)存描述懈息。
老年代的內(nèi)存占用為100M左右。 按照整個(gè)堆大小是老年代(FullGC)之后的3-4倍計(jì)算的話摹恰,設(shè)置各代的內(nèi)存情況如下:
Xmx=512m Xms=512m Xmn=128m PermSize=128m 老年代的大小為 (512-128=384m)為老年代存活對(duì)象大小的3倍左右
調(diào)整之后的漓拾,heap情況
GC情況如下:
YGC 差不多在10s左右觸發(fā)一次阁最。每次YGC平均耗時(shí)大約9.41ms戒祠『Я剑可接受。
FGC平均耗時(shí):0.016s/2=8ms
整體的GC耗時(shí)減少姜盈。但GC頻率比之前的2G時(shí)的要多了一些低千。
注: 看上述GC的時(shí)候,發(fā)現(xiàn)YGC的次數(shù)突然會(huì)增多很多個(gè)馏颂,比如 從1359次到了1364次示血。具體原因是?
總結(jié):
在內(nèi)存相對(duì)緊張的情況下救拉,可以按照上述的方式來(lái)進(jìn)行內(nèi)存的調(diào)優(yōu)难审, 找到一個(gè)在GC頻率和GC耗時(shí)上都可接受的一個(gè)內(nèi)存設(shè)置,可以用較小的內(nèi)存滿足當(dāng)前的服務(wù)需要
但當(dāng)內(nèi)存相對(duì)寬裕的時(shí)候亿絮,可以相對(duì)給服務(wù)多增加一點(diǎn)內(nèi)存告喊,可以減少GC的頻率,GC的耗時(shí)相應(yīng)會(huì)增加一些派昧。 一般要求低延時(shí)的可以考慮多設(shè)置一點(diǎn)內(nèi)存黔姜, 對(duì)延時(shí)要求不高的,可以按照上述方式設(shè)置較小內(nèi)存蒂萎。
補(bǔ)充:
永久代(方法區(qū))并不在堆內(nèi)秆吵,所以之前有看過(guò)一篇文章中描述的 整個(gè)堆大小=年輕代+年老代+永久代的描述是不正確的。
轉(zhuǎn)自:
https://blog.csdn.net/losetowin/article/details/78569001
補(bǔ)充
-verbose:gc 現(xiàn)實(shí)垃圾收集信息
-Xloggc:gc.log 指定垃圾收集日志文件
-Xmn:young generation的heap大小五慈,一般設(shè)置為Xmx的3纳寂、4分之一
-XX:SurvivorRatio=2 :生還者池的大小,默認(rèn)是2,如果垃圾回收變成了瓶頸泻拦,您可以嘗試定制生成池設(shè)置
-XX:NewSize: 新生成的池的初始大小毙芜。 缺省值為2M。
-XX:MaxNewSize: 新生成的池的最大大小聪轿。 缺省值為32M爷肝。
+XX:AggressiveHeap 會(huì)使得 Xms沒(méi)有意義。這個(gè)參數(shù)讓jvm忽略Xmx參數(shù),瘋狂地吃完一個(gè)G物理內(nèi)存,再吃盡一個(gè)G的swap陆错。
-Xss:每個(gè)線程的Stack大小灯抛,“-Xss 15120” 這使得JBoss每增加一個(gè)線程(thread)就會(huì)立即消耗15M內(nèi)存,而最佳值應(yīng)該是128K,默認(rèn)值好像是512k.