JVM相關(5)-- JVM性能優(yōu)化

5钞螟、JVM性能優(yōu)化

Java啟動參數(shù)共分為三類:

其一是標準參數(shù)(-),所有的JVM實現(xiàn)都必須實現(xiàn)這些參數(shù)的功能绸狐,而且向后兼容卤恳;

其二是非標準參數(shù)(-X),默認jvm實現(xiàn)這些參數(shù)的功能寒矿,但是并不保證所有jvm實現(xiàn)都滿足突琳,且不保證向后兼容;

其三是非Stable參數(shù)(-XX)符相,此類參數(shù)各個jvm實現(xiàn)會有所不同拆融,將來可能會隨時取消,需要慎重使用啊终。


JVM標準參數(shù)(-)

JVM的標準參數(shù)都是以”-“開頭镜豹,通過輸入”java -help”或者”java -?”,可以查看JVM標準參數(shù)列表蓝牲。

JVM非標準參數(shù)(-X)

通過”java -X”可以輸出非標準參數(shù)列表逛艰,如下所示:

JVM非Stable參數(shù)(-XX)

Java 6(update 21 oder 21之后)版本, HotSpot JVM 提供給了兩個新的參數(shù)搞旭,在JVM啟動后散怖,在命令行中可以輸出所有XX參數(shù)和值:

java -XX:+PrintFlagsInitial?-XX:+PrintFlagsInitial>>1.txt


這些參數(shù)可以被松散的聚合成三類:

行為參數(shù)(Behavioral Options):用于改變jvm的一些基礎行為菇绵;

性能調優(yōu)(Performance Tuning):用于jvm的性能調優(yōu);

調試參數(shù)(Debugging Options):一般用于打開跟蹤镇眷、打印咬最、輸出等jvm參數(shù),用于顯示jvm更加詳細的信息欠动;


行為參數(shù)(功能開關)

-XX:-DisableExplicitGC? 禁止調用System.gc()永乌;但jvm的gc仍然有效

-XX:+MaxFDLimit 最大化文件描述符的數(shù)量限制

-XX:+ScavengeBeforeFullGC?? 新生代GC優(yōu)先于Full GC執(zhí)行

-XX:+UseGCOverheadLimit 在拋出OOM之前限制jvm耗費在GC上的時間比例

-XX:-UseConcMarkSweepGC 對老生代采用并發(fā)標記交換算法進行GC

-XX:-UseParallelGC? 啟用并行GC

-XX:-UseParallelOldGC?? 對Full GC啟用并行,當-XX:-UseParallelGC啟用時該項自動啟用

-XX:-UseSerialGC??? 啟用串行GC

-XX:+UseThreadPriorities??? 啟用本地線程優(yōu)先級


性能調優(yōu)

-XX:LargePageSizeInBytes=4m 設置用于Java堆的大頁面尺寸

-XX:MaxHeapFreeRatio=70 GC后java堆中空閑量占的最大比例

-XX:MaxNewSize=size 新生成對象能占用內存的最大值

-XX:MaxPermSize=64m 老生代對象能占用內存的最大值

-XX:MinHeapFreeRatio=40 GC后java堆中空閑量占的最小比例

-XX:NewRatio=2? 新生代內存容量與老生代內存容量的比例

-XX:NewSize=125m? 新生代對象生成時占用內存的默認值

-XX:ReservedCodeCacheSize=32m??保留代碼占用的內存容量

-XX:ThreadStackSize=512 設置線程棧大小具伍,若為0則使用系統(tǒng)默認值

-XX:+UseLargePages? 使用大頁面內存


調試參數(shù)

-XX:-CITime 打印消耗在JIT編譯的時間

-XX:ErrorFile=./hs_err_pid<pid>.log 保存錯誤日志或者數(shù)據(jù)到文件中

-XX:-ExtendedDTraceProbes?? 開啟solaris特有的dtrace探針

-XX:HeapDumpPath=./java_pid.hprof? 指定導出堆信息時的路徑或文件名

-XX:-HeapDumpOnOutOfMemoryError 當首次遭遇OOM時導出此時堆中相關信息

-XX:OnError="<cmd args>;<cmd args>" 出現(xiàn)致命ERROR之后運行自定義命令

-XX:OnOutOfMemoryError=";"? 當首次遭遇OOM時執(zhí)行自定義命令

-XX:-PrintClassHistogram??? 遇到Ctrl-Break后打印類實例的柱狀信息翅雏,與jmap -histo功能相同

-XX:-PrintConcurrentLocks?? 遇到Ctrl-Break后打印并發(fā)鎖的相關信息,與jstack -l功能相同

-XX:-PrintCommandLineFlags? 打印在命令行中出現(xiàn)過的標記

-XX:-PrintCompilation?? 當一個方法被編譯時打印相關信息

-XX:-PrintGC??? 每次GC時打印相關信息

-XX:-PrintGC Details??? 每次GC時打印詳細信息

-XX:-PrintGCTimeStamps? 打印每次GC的時間戳

-XX:-TraceClassLoading? 跟蹤類的加載信息

-XX:-TraceClassLoadingPreorder?跟蹤被引用到的所有類的加載信息

-XX:-TraceClassResolution?? 跟蹤常量池

-XX:-TraceClassUnloading??? 跟蹤類的卸載信息

-XX:-TraceLoaderConstraints 跟蹤類加載器約束的相關信息


GC優(yōu)化的目的有兩個:

* 將轉移到老年代的對象數(shù)量降低到最腥搜俊望几;

* 減少full GC的執(zhí)行時間;


為了達到上面的目的萤厅,一般地橄抹,你需要做的事情有:

* 減少使用全局變量和大對象;

* 調整新生代的大小到最合適惕味;

* 設置老年代的大小為最合適楼誓;

* 選擇合適的GC收集器;


進行監(jiān)控和調優(yōu)的一般步驟為:

1名挥,監(jiān)控GC的狀態(tài)

使用各種JVM工具疟羹,查看當前日志,分析當前JVM參數(shù)設置禀倔,并且分析當前堆內存快照和gc日志榄融,根據(jù)實際的各區(qū)域內存劃分和GC執(zhí)行時間,覺得是否進行優(yōu)化蹋艺;

常用JVM工具:

(1)jstat

jstat可以實時顯示本地或遠程JVM進程中類裝載剃袍、內存黄刚、垃圾收集捎谨、JIT編譯等數(shù)據(jù)(如果要顯示遠程JVM信息,需要遠程主機開啟RMI支持)憔维。如果在服務啟動時沒有指定啟動參數(shù)-verbose:gc涛救,則可以用jstat實時查看gc情況。

jstat有如下選項:

-class:監(jiān)視類裝載业扒、卸載數(shù)量检吆、總空間及類裝載所耗費的時間

-gc:監(jiān)聽Java堆狀況,包括Eden區(qū)程储、兩個Survivor區(qū)蹭沛、老年代臂寝、永久代等的容量,以用空間摊灭、GC時間合計等信息

-gccapacity:監(jiān)視內容與-gc基本相同咆贬,但輸出主要關注java堆各個區(qū)域使用到的最大和最小空間

-gcutil:監(jiān)視內容與-gc基本相同,但輸出主要關注已使用空間占總空間的百分比

-gccause:與-gcutil功能一樣帚呼,但是會額外輸出導致上一次GC產(chǎn)生的原因

-gcnew:監(jiān)視新生代GC狀況

-gcnewcapacity:監(jiān)視內同與-gcnew基本相同掏缎,輸出主要關注使用到的最大和最小空間

-gcold:監(jiān)視老年代GC情況

-gcoldcapacity:監(jiān)視內同與-gcold基本相同,輸出主要關注使用到的最大和最小空間

-gcpermcapacity:輸出永久代使用到最大和最小空間

-compiler:輸出JIT編譯器編譯過的方法煤杀、耗時等信息

-printcompilation:輸出已經(jīng)被JIT編譯的方法

命令格式:jstat [option vmid [interval[s|ms] [count]]]

(2)jmap

用于顯示當前Java堆和永久代的詳細信息(如當前使用的收集器眷蜈,當前的空間使用率等)

?? -dump:生成java堆轉儲快照

?? -heap:顯示java堆詳細信息(只在Linux/Solaris下有效)

?? -F:當虛擬機進程對-dump選項沒有響應時,可使用這個選項強制生成dump快照(只在Linux/Solaris下有效)

(3)jstack

用于生成當前JVM的所有線程快照沈自,線程快照是虛擬機每一條線程正在執(zhí)行的方法,目的是定位線程出現(xiàn)長時間停頓的原因酌儒。

-F:當正常輸出的請求不被響應時,強制輸出線程堆棧

-l:除堆棧外酥泛,顯示關于鎖的附加信息

-m:如果調用到本地方法的話今豆,可以顯示C/C++的堆棧

命令格式:jstack [option] vmid


2,分析結果柔袁,判斷是否需要優(yōu)化

如果各項參數(shù)設置合理呆躲,系統(tǒng)沒有超時日志出現(xiàn),GC頻率不高捶索,GC耗時不高插掂,那么沒有必要進行GC優(yōu)化;如果GC時間超過1-3秒腥例,或者頻繁GC辅甥,則必須優(yōu)化;

注:如果滿足下面的指標燎竖,則一般不需要進行GC:

?? Minor GC執(zhí)行時間不到50ms璃弄;

?? Minor GC執(zhí)行不頻繁,約10秒一次构回;

?? Full GC執(zhí)行時間不到1s夏块;

?? Full GC執(zhí)行頻率不算頻繁,不低于10分鐘1次纤掸;


3脐供,調整GC類型和內存分配

如果內存分配過大或過小,或者采用的GC收集器比較慢借跪,則應該優(yōu)先調整這些參數(shù)政己,并且先找1臺或幾臺機器進行beta,然后比較優(yōu)化過的機器和沒有優(yōu)化的機器的性能對比掏愁,并有針對性的做出最后選擇歇由;


4卵牍,不斷的分析和調整

通過不斷的試驗和試錯,分析并找到最合適的參數(shù)


5沦泌,全面應用參數(shù)

如果找到了最合適的參數(shù)辽慕,則將這些參數(shù)應用到所有服務器,并進行后續(xù)跟蹤赦肃。


調優(yōu)實例:

實例1:

筆者昨日發(fā)現(xiàn)部分開發(fā)測試機器出現(xiàn)異常:java.lang.OutOfMemoryError: GC overhead limit exceeded溅蛉,這個異常代表:

GC為了釋放很小的空間卻耗費了太多的時間,其原因一般有兩個:1他宛,堆太小船侧,2,有死循環(huán)或大對象厅各;

筆者首先排除了第2個原因镜撩,因為這個應用同時是在線上運行的,如果有問題队塘,早就掛了袁梗。所以懷疑是這臺機器中堆設置太小憔古;

使用ps -ef |grep "java"查看遮怜,發(fā)現(xiàn):

該應用的堆區(qū)設置只有768m,而機器內存有2g鸿市,機器上只跑這一個java應用锯梁,沒有其他需要占用內存的地方。另外焰情,這個應用比較大陌凳,需要占用的內存也比較多;

筆者通過上面的情況判斷内舟,只需要改變堆中各區(qū)域的大小設置即可合敦,于是改成下面的情況:

跟蹤運行情況發(fā)現(xiàn),相關異常沒有再出現(xiàn)验游;


實例2:

一個服務系統(tǒng)充岛,經(jīng)常出現(xiàn)卡頓,分析原因批狱,發(fā)現(xiàn)Full GC時間太長:

jstat -gcutil:

S0???? ?S1???E???? O?????? ?P??????? YGC YGCT??????FGC??FGCT?GCT

12.16 0.00 5.18 63.78 20.32?54?? ???2.047???????5????????6.946? ?8.993

分析上面的數(shù)據(jù)裸准,發(fā)現(xiàn)Young GC執(zhí)行了54次展东,耗時2.047秒赔硫,每次Young GC耗時37ms,在正常范圍盐肃,而Full GC執(zhí)行了5次爪膊,耗時6.946秒权悟,每次平均1.389s,數(shù)據(jù)顯示出來的問題是:Full GC耗時較長推盛,分析該系統(tǒng)的是指發(fā)現(xiàn)峦阁,NewRatio=9,也就是說耘成,新生代和老生代大小之比為1:9榔昔,這就是問題的原因:

1,新生代太小瘪菌,導致對象提前進入老年代撒会,觸發(fā)老年代發(fā)生Full GC;

2师妙,老年代較大诵肛,進行Full GC時耗時較大;

優(yōu)化的方法是調整NewRatio的值默穴,調整到4怔檩,發(fā)現(xiàn)Full GC沒有再發(fā)生,只有Young GC在執(zhí)行蓄诽。這就是把對象控制在新生代就清理掉薛训,沒有進入老年代(這種做法對一些應用是很有用的,但并不是對所有應用都要這么做)


實例3:

一應用在性能測試過程中仑氛,發(fā)現(xiàn)內存占用率很高许蓖,F(xiàn)ull GC頻繁,使用sudo -u admin-H? jmap -dump:format=b,file=文件名.hprof pid 來dump內存调衰,生成dump文件膊爪,并使用Eclipse下的mat差距進行分析,發(fā)現(xiàn):

從圖中可以看出嚎莉,這個線程存在問題米酬,隊列LinkedBlockingQueue所引用的大量對象并未釋放,導致整個線程占用內存高達378m趋箩,此時通知開發(fā)人員進行代碼優(yōu)化赃额,將相關對象釋放掉即可。


JVM參數(shù)設置建議如下:

(1)-Xms和-Xmx的值設置成相等叫确,堆大小默認為-Xms指定的大小跳芳,默認空閑堆內存小于40%時,JVM會擴大堆到-Xmx指定的大兄衩恪飞盆;空閑堆內存大于70%時,JVM會減小堆到-Xms指定的大小。如果在Full GC后滿足不了內存需求會動態(tài)調整吓歇,這個階段比較耗費資源孽水。

(2)新生代盡量設置大一些,讓對象在新生代多存活一段時間城看,每次Minor GC 都要盡可能多的收集垃圾對象女气,防止或延遲對象進入老年代的機會,以減少應用程序發(fā)生Full GC的頻率测柠。

(3)老年代如果使用CMS收集器炼鞠,新生代可以不用太大,因為CMS的并行收集速度也很快轰胁,收集過程比較耗時的并發(fā)標記和并發(fā)清除階段都可以與用戶線程并發(fā)執(zhí)行簇搅。

(4)方法區(qū)大小的設置,1.6之前的需要考慮系統(tǒng)運行時動態(tài)增加的常量软吐、靜態(tài)變量等瘩将,1.7只要差不多能裝下啟動時和后期動態(tài)加載的類信息就行。


代碼實現(xiàn)方面凹耙,性能出現(xiàn)問題比如程序等待姿现、內存泄漏除了JVM配置可能存在問題,代碼實現(xiàn)上也有很大關系:

(1)避免創(chuàng)建過大的對象及數(shù)組:過大的對象或數(shù)組在新生代沒有足夠空間容納時會直接進入老年代肖抱,如果是短命的大對象备典,會提前出發(fā)Full GC。

(2)避免同時加載大量數(shù)據(jù)意述,如一次從數(shù)據(jù)庫中取出大量數(shù)據(jù)提佣,或者一次從Excel中讀取大量記錄,可以分批讀取荤崇,用完盡快清空引用拌屏。

(3)當集合中有對象的引用,這些對象使用完之后要盡快把集合中的引用清空术荤,這些無用對象盡快回收避免進入老年代倚喂。

(4)可以在合適的場景(如實現(xiàn)緩存)采用軟引用、弱引用瓣戚,比如用軟引用來為ObjectA分配實例:SoftReference objectA=new SoftReference(); 在發(fā)生內存溢出前端圈,會將objectA列入回收范圍進行二次回收,如果這次回收還沒有足夠內存子库,才會拋出內存溢出的異常舱权。

(5)避免產(chǎn)生死循環(huán),產(chǎn)生死循環(huán)后仑嗅,循環(huán)體內可能重復產(chǎn)生大量實例宴倍,導致內存空間被迅速占滿张症。

(6)盡量避免長時間等待外部資源(數(shù)據(jù)庫、網(wǎng)絡啊楚、設備資源等)的情況,縮小對象的生命周期浑彰,避免進入老年代恭理,如果不能及時返回結果可以適當采用異步處理的方式等。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末郭变,一起剝皮案震驚了整個濱河市颜价,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诉濒,老刑警劉巖周伦,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異未荒,居然都是意外死亡专挪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門片排,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寨腔,“玉大人,你說我怎么就攤上這事率寡∑嚷” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵冶共,是天一觀的道長乾蛤。 經(jīng)常有香客問我,道長捅僵,這世上最難降的妖魔是什么家卖? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮庙楚,結果婚禮上篡九,老公的妹妹穿的比我還像新娘。我一直安慰自己醋奠,他們只是感情好榛臼,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窜司,像睡著了一般沛善。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上塞祈,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天金刁,我揣著相機與錄音,去河邊找鬼。 笑死尤蛮,一個胖子當著我的面吹牛媳友,可吹牛的內容都是我干的骤视。 我是一名探鬼主播滨彻,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缆毁,長吁一口氣:“原來是場噩夢啊……” “哼肺蔚!你這毒婦竟也來了翼闹?” 一聲冷哼從身側響起霍殴,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坟岔,失蹤者是張志新(化名)和其女友劉穎顶瞳,沒想到半個月后看靠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赶促,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年挟炬,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸥滨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡谤祖,死狀恐怖爵赵,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情泊脐,我是刑警寧澤空幻,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站容客,受9級特大地震影響秕铛,放射性物質發(fā)生泄漏。R本人自食惡果不足惜缩挑,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一但两、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧供置,春花似錦谨湘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至续担,卻和暖如春擅耽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背物遇。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工乖仇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憾儒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓乃沙,卻偏偏與公主長得像起趾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子警儒,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容

  • 轉載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,373評論 1 56
  • Java 虛擬機有自己完善的硬件架構, 如處理器训裆、堆棧、寄存器等冷蚂,還具有相應的指令系統(tǒng)缭保。JVM 屏蔽了與具體操作系...
    尹小凱閱讀 1,695評論 0 10
  • 內存溢出和內存泄漏的區(qū)別 內存溢出:out of memory汛闸,是指程序在申請內存時蝙茶,沒有足夠的內存空間供其使用,...
    Aimerwhy閱讀 744評論 0 1
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight閱讀 1,427評論 1 0
  • 一 诸老、java虛擬機底層結構詳解 我們知道隆夯,一個JVM實例的行為不光是它自己的事,還涉及到它的子系統(tǒng)别伏、存儲區(qū)域蹄衷、...
    葡萄喃喃囈語閱讀 1,488評論 0 4