摘要:內(nèi)存設(shè)置現(xiàn)在線上業(yè)務(wù)系統(tǒng)基本物理內(nèi)存都是夠用的,不過(guò)物盡其用,我們調(diào)優(yōu)就是爭(zhēng)取讓每空間都發(fā)揮出最大的作用。區(qū)總內(nèi)存減去一個(gè)區(qū)的大小不宜過(guò)大,否則可能把物理內(nèi)存耗光。
在生產(chǎn)系統(tǒng)中,高吞吐和低延遲一直都是JVM調(diào)優(yōu)的最終目標(biāo),但這兩者恰恰又是相悖的,魚和熊掌不可兼得,所以在調(diào)優(yōu)之前要清楚舍誰(shuí)而取誰(shuí)。一般計(jì)算任務(wù)和組件服務(wù)會(huì)偏向高吞吐,而web展示則偏向低延遲才會(huì)帶來(lái)更好的用戶體驗(yàn)。
本文從性能和經(jīng)驗(yàn)上來(lái)分享一下JVM參數(shù)的設(shè)置。
調(diào)優(yōu)之前可以先用-XX:+PrintFlagsFinal來(lái)查看虛擬機(jī)是否默認(rèn)開啟某參數(shù),不同版本的JDK可能虛擬機(jī)默認(rèn)開啟的參數(shù)也略有不同,新學(xué)習(xí)一條神奇的參數(shù)的時(shí)候可以先去查找一下參數(shù)是否默認(rèn)開啟了。
$ java -server -XX:+PrintCommandLineFlags |grep XXXXXXX
也可以通過(guò)jinfo口令 jinfo -flags [pid]來(lái)查看
GC策略目前來(lái)看還是CMS當(dāng)?shù)溃掏侣屎晚憫?yīng)時(shí)間闊以兼顧,G1嘛,雞丸雞丸,至今并沒有展現(xiàn)出one的實(shí)力,不過(guò)據(jù)貴里某P8講G1在大堆(20G+)下表現(xiàn)更突出,停頓會(huì)顯著降低,可能之后隨著高內(nèi)存越來(lái)越經(jīng)濟(jì)和普及,G1才能名副其實(shí)的稱為雞one。
廢話少說(shuō),
-XX:+UseConcMarkSweepGC
設(shè)置CMS做為垃圾收集,CMS開啟后默認(rèn)的新生代回收是ParNew,如果CMS出現(xiàn)“Concurrent Mode Failure”了還會(huì)啟用Serial Old做備胎。
-XX:CMSInitiatingOccupancyFraction=75
默認(rèn)值是68,這個(gè)可以根據(jù)實(shí)際調(diào)優(yōu)目標(biāo)來(lái)調(diào)整,這個(gè)參數(shù)就比較應(yīng)開始提到的,調(diào)優(yōu)目標(biāo)是降低延遲還是提高吞吐,如果是為了降低單次GC延遲,那么這個(gè)值闊以再往低了調(diào)一些,不過(guò)調(diào)的太高可能導(dǎo)致老年代剩余空間不夠招呼并發(fā)收集產(chǎn)生的浮動(dòng)垃圾而頻繁的觸發(fā)Full GC。
-XX:+UseCMSInitiatingOccupancyOnly
使用CMS的話這個(gè)參數(shù)一定要加上,一定要加上,一定要加上,重要的事情說(shuō)三遍,否則虛擬機(jī)后面還是會(huì)自作聰明的自己計(jì)算上個(gè)參數(shù)的比值。
-XX:MaxTenuringThreshold=5
默認(rèn)15,這個(gè)值是設(shè)置新生代對(duì)象存活了多少次young GC后可以進(jìn)入老年代,值設(shè)的高的話可以使老年代增長(zhǎng)緩慢,但YGC的次數(shù)會(huì)明顯增多,如果清楚YGC的執(zhí)行頻率和大多數(shù)對(duì)象的最長(zhǎng)生命周期,這個(gè)值可以設(shè)低些,讓那些對(duì)象早點(diǎn)進(jìn)入老年代。
可以用-XX:+PrintTenuringDistribution來(lái)觀察一段時(shí)間,然后調(diào)整合適的值。
ps:有一種野路子是此值設(shè)為0,新生代GC次數(shù)少,速度快,就是老年代GC會(huì)更加頻繁一些,不過(guò)也最大利用了并發(fā)GC。不過(guò)我沒在生產(chǎn)這么搞過(guò),效果有待驗(yàn)證。
-XX:+ExplicitGCInvokesConcurrent
這個(gè)參數(shù)是用來(lái)代替,-XX:DisableExplicitGC的,NIO許多地方會(huì)顯示的調(diào)用System.gc()來(lái)觸發(fā)一次Full GC。許多時(shí)候別的地方優(yōu)化一萬(wàn)點(diǎn)都賠不起這兒調(diào)上幾次的。ExplicitGCInvokesConcurrent這個(gè)參數(shù)是配合CMS使用的,開啟后System.gc()還是會(huì)觸發(fā)Full GC,不過(guò)并不是一個(gè)完全的stop-the-world的Full GC,而是并發(fā)的CMS GC。
內(nèi)存設(shè)置現(xiàn)在線上業(yè)務(wù)系統(tǒng)基本物理內(nèi)存都是夠用的,不過(guò)物盡其用,我們調(diào)優(yōu)就是爭(zhēng)取讓每M空間都發(fā)揮出最大的作用。內(nèi)存的設(shè)置還是最直觀見效的。
-Xmx500m ,-Xms500m
最大堆內(nèi)存和最小堆內(nèi)存,這兩個(gè)值要設(shè)的一致,避免虛擬機(jī)還要?jiǎng)討B(tài)的計(jì)算分配內(nèi)存空間。
PS:堆也不是越大越好,大堆帶來(lái)的后果就是單次GC會(huì)較長(zhǎng)。
-Xmn250m
新生代大小,非G1收集器可以設(shè)置這個(gè)值,G1的官方建議是不要顯示分配新生代和老年代空間大小,因?yàn)镚1會(huì)通過(guò)網(wǎng)格化內(nèi)存來(lái)動(dòng)態(tài)分配new/old區(qū),官方認(rèn)為不設(shè)置new size是最佳實(shí)踐。
-Xss2m
每個(gè)線程的棧空間大小,默認(rèn)值是1m,一般不需要設(shè)置,除非有遞歸方法存在可能會(huì)爆棧。
-XX:PermSize=128m,-XX:MaxPermSize=256m
JDK8之前永久代的空間設(shè)置,Spring框架了大量依賴AOP的實(shí)現(xiàn)都用的動(dòng)態(tài)代理生成字節(jié)碼,所以設(shè)個(gè)最大值求保險(xiǎn)。
不過(guò)JDK8之后取消了永久代,改為元空間(MetaSpace),這塊屬于本地內(nèi)存,理論上可以利用系統(tǒng)剩余的所有內(nèi)存,不過(guò)跑了多個(gè)實(shí)例的話還是要設(shè)置一下為妙:
-XX:MetaspaceSize=128m,-XX:MaxMetaspaceSize=256m
-XX:MaxDirectMemorySize=128m
這個(gè)屬于對(duì)外內(nèi)存,可以合理控制大小。Heap區(qū)總內(nèi)存減去一個(gè)Survivor區(qū)的大小,不宜過(guò)大,否則可能heap size + Direct Memory Size把物理內(nèi)存耗光。
-XX:SurvivorRatio=7
默認(rèn)是8,新生代中Eden與Survivor的比值,過(guò)大的話可能Survivor存不下臨時(shí)對(duì)象而頻繁觸發(fā)分配擔(dān)保。可以根據(jù)GC日志看實(shí)際情況。
PS:
關(guān)于內(nèi)存大小的設(shè)置完全要根據(jù)各個(gè)機(jī)器和應(yīng)用自身的情況來(lái)設(shè)置。
可以通過(guò)jstat -gc [pid] 2000 30,每2s輸出一次一共輸出30次內(nèi)存情況,看看各個(gè)區(qū)域增長(zhǎng)的速度,最大空間等數(shù)據(jù)來(lái)修改內(nèi)存設(shè)置。
監(jiān)控參數(shù)還是需要的,不然有時(shí)候線上偶爾OOM了真的不好重現(xiàn)。
-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath={path}
OOM的時(shí)候會(huì)輸出dump快照到{path}目錄,只需要指向目錄,文件名JVM會(huì)保持唯一性。
-XX:+PrintGCDetails,-Xloggc:logs/gc.log,-XX:+PrintGCTimeStamps,-XX:+PrintGCDateStamps
打印GC詳細(xì)記錄,-XX:+PrintGC 這個(gè)口令是簡(jiǎn)單GC日志,為了更容易定位問題,我們開啟Details模式,-Xloggc是把gc日志輸出到指定文件。
-XX:+PrintGCTimeStamps顯示的時(shí)間代表JVM啟動(dòng)至記錄日志的時(shí)間。
-XX:+PrintGCDateStamps則會(huì)添加上每行信息的絕對(duì)日期。
其實(shí)開啟了-Xloggc的話會(huì)隱式的開啟-XX:+PrintGCTimeStamps,不過(guò)為了防止各版本JVM改動(dòng)差異,還是顯示的設(shè)置出來(lái)保險(xiǎn)。
-XX:-OmitStackTraceInFastThrow
這是個(gè)比較容易被忽略的參數(shù),而沒有經(jīng)驗(yàn)的話又往往很難定位到原因。
JDK5之后JVM對(duì)異常做了一個(gè)優(yōu)化,對(duì)于一些頻繁拋出的異常,JIT重新編譯后會(huì)拋出沒有堆棧信息的異常,-server模式下是默認(rèn)開啟的,因此在頻繁拋出某個(gè)異常一段時(shí)間后,該優(yōu)化開始起作用,即只拋出沒有堆棧的異常信息。
但由于該優(yōu)化是JIT編譯后才啟用的,所以開始該異常的拋出是有完整堆棧信息的,但運(yùn)行一段時(shí)間可能發(fā)現(xiàn)沒有任何堆棧信息,很難定位,初次遇到很容易摸不到頭腦。
可以使用-XX:-OmitStackTraceInFastThrow來(lái)關(guān)閉該項(xiàng)優(yōu)化。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/76120.html
摘要:原文鏈接本篇是專家系列的第三篇。但是,請(qǐng)記住調(diào)優(yōu)是不得已時(shí)的選擇。縮短耗時(shí)的單次執(zhí)行與相比,耗時(shí)有較明顯的增加。創(chuàng)建文件過(guò)程中,進(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...
面試官:今天要不來(lái)聊聊JVM調(diào)優(yōu)相關(guān)的吧?面試官:你曾經(jīng)在生產(chǎn)環(huán)境下有過(guò)調(diào)優(yōu)JVM的經(jīng)歷嗎?候選者:沒有面試官:...候選者:嗯...是這樣的,我們一般優(yōu)化系統(tǒng)的思路是這樣的候選者:1. 一般來(lái)說(shuō)關(guān)系型數(shù)據(jù)庫(kù)是先到瓶頸,首先排查是否為數(shù)據(jù)庫(kù)的問題候選者:(這個(gè)過(guò)程中就需要評(píng)估自己建的索引是否合理、是否需要引入分布式緩存、是否需要分庫(kù)分表等等)候選者:2. 然后,我們會(huì)考慮是否需要擴(kuò)容(橫向和縱向都...
閱讀 2135·2019-08-29 16:53
閱讀 2712·2019-08-29 16:07
閱讀 2054·2019-08-29 13:13
閱讀 3277·2019-08-26 13:57
閱讀 1342·2019-08-26 13:31
閱讀 2446·2019-08-26 13:22
閱讀 1232·2019-08-26 11:43
閱讀 2095·2019-08-23 17:14