內(nèi)存溢出的幾種原因和解決辦法+jvm運(yùn)行參數(shù)配置詳解

本文抄自:https://blog.csdn.net/cp_panda_5/article/details/79613870语御,請(qǐng)讀者移步查看原文纤控,本文是為防止該文失效同時(shí)為了本人方便查看刻撒,做的備份声怔。

對(duì)于JVM的內(nèi)存寫(xiě)過(guò)的文章已經(jīng)有點(diǎn)多了,而且有點(diǎn)爛了,不過(guò)說(shuō)那么多大多數(shù)在解決OOM的情況,于此,本文就只闡述這個(gè)內(nèi)容婚瓜,攜帶一些分析和理解和部分?jǐn)U展內(nèi)容巴刻,也就是JVM宕機(jī)中的一些問(wèn)題,OK,下面說(shuō)下OOM的常見(jiàn)情況:
第一類內(nèi)存溢出妈经,也是大家認(rèn)為最多,第一反應(yīng)認(rèn)為是的內(nèi)存溢出爆哑,就是堆棧溢出:

那什么樣的情況就是堆棧溢出呢泪漂?當(dāng)你看到下面的關(guān)鍵字的時(shí)候它就是堆棧溢出了:

java.lang.OutOfMemoryError: ......java heap space.....

也就是當(dāng)你看到heap相關(guān)的時(shí)候就肯定是堆棧溢出了廊营,此時(shí)如果代碼沒(méi)有問(wèn)題的情況下,適當(dāng)調(diào)整-Xmx和-Xms是可以避免的萝勤,不過(guò)一定是代碼沒(méi)有問(wèn)題的前提露筒,為什么會(huì)溢出呢,要么代碼有問(wèn)題慎式,要么訪問(wèn)量太多并且每個(gè)訪問(wèn)的時(shí)間太長(zhǎng)或者數(shù)據(jù)太多,導(dǎo)致數(shù)據(jù)釋放不掉趟径,因?yàn)槔厥掌魇且业侥切┦抢拍芑厥毡窭簦@里它不會(huì)認(rèn)為這些東西是垃圾,自然不會(huì)去回收了蜗巧;主意這個(gè)溢出之前掌眠,可能系統(tǒng)會(huì)提前先報(bào)錯(cuò)關(guān)鍵字為:

java.lang.OutOfMemoryError:GC over head limit exceeded

這種情況是當(dāng)系統(tǒng)處于高頻的GC狀態(tài),而且回收的效果依然不佳的情況幕屹,就會(huì)開(kāi)始報(bào)這個(gè)錯(cuò)誤蓝丙,這種情況一般是產(chǎn)生了很多不可以被釋放的對(duì)象,有可能是引用使用不當(dāng)導(dǎo)致望拖,或申請(qǐng)大對(duì)象導(dǎo)致渺尘,但是java heap space的內(nèi)存溢出有可能提前不會(huì)報(bào)這個(gè)錯(cuò)誤,也就是可能內(nèi)存就直接不夠?qū)е滤得簦皇歉哳lGC鸥跟,因?yàn)間c時(shí)間消耗的較多。解決這種問(wèn)題兩種方法是盔沫,增加參數(shù)医咨,-XX:-UseGCOverheadLimit,關(guān)閉這個(gè)特性迅诬,同時(shí)增加heap大小腋逆,-Xmx1024m。

第二類內(nèi)存溢出侈贷,PermGen的溢出惩歉,或者PermGen 滿了的提示,你會(huì)看到這樣的關(guān)鍵字:

關(guān)鍵信息為:

java.lang.OutOfMemoryError: PermGen space

原因:系統(tǒng)的代碼非常多或引用的第三方包非常多俏蛮、或代碼中使用了大量的常量撑蚌、或通過(guò)intern注入常量、或者通過(guò)動(dòng)態(tài)代碼加載等方法搏屑,導(dǎo)致常量池的膨脹争涌,雖然JDK 1.5以后可以通過(guò)設(shè)置對(duì)永久帶進(jìn)行回收,但是我們希望的是這個(gè)地方是不做GC的辣恋,它夠用就行亮垫,所以一般情況下盡量少做類似的操作模软,所以在面對(duì)這種情況常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。

第三類內(nèi)存溢出:在使用ByteBuffer中的allocateDirect()的時(shí)候會(huì)用到饮潦,很多javaNIO的框架中被封裝為其他的方法

溢出關(guān)鍵字:

java.lang.OutOfMemoryError: Direct buffer memory
如果你在直接或間接使用了ByteBuffer中的allocateDirect方法的時(shí)候燃异,而不做clear的時(shí)候就會(huì)出現(xiàn)類似的問(wèn)題,常規(guī)的引用程序IO輸出存在一個(gè)內(nèi)核態(tài)與用戶態(tài)的轉(zhuǎn)換過(guò)程继蜡,也就是對(duì)應(yīng)直接內(nèi)存與非直接內(nèi)存回俐,如果常規(guī)的應(yīng)用程序你要將一個(gè)文件的內(nèi)容輸出到客戶端需要通過(guò)OS的直接內(nèi)存轉(zhuǎn)換拷貝到程序的非直接內(nèi)存(也就是heap中),然后再輸出到直接內(nèi)存由操作系統(tǒng)發(fā)送出去稀并,而直接內(nèi)存就是由OS和應(yīng)用程序共同管理的仅颇,而非直接內(nèi)存可以直接由應(yīng)用程序自己控制的內(nèi)存,jvm垃圾回收不會(huì)回收掉直接內(nèi)存這部分的內(nèi)存碘举,所以要注意了哦忘瓦。

如果經(jīng)常有類似的操作,可以考慮設(shè)置參數(shù):-XX:MaxDirectMemorySize

第四類內(nèi)存溢出錯(cuò)誤:

溢出關(guān)鍵字:

java.lang.StackOverflowError

這個(gè)參數(shù)直接說(shuō)明一個(gè)內(nèi)容引颈,就是-Xss太小了政冻,我們申請(qǐng)很多局部調(diào)用的棧針等內(nèi)容是存放在用戶當(dāng)前所持有的線程中的,線程在jdk 1.4以前默認(rèn)是256K线欲,1.5以后是1M,如果報(bào)這個(gè)錯(cuò)汽摹,只能說(shuō)明-Xss設(shè)置得太小李丰,當(dāng)然有些廠商的JVM不是這個(gè)參數(shù),本文僅僅針對(duì)Hotspot VM而已逼泣;不過(guò)在有必要的情況下可以對(duì)系統(tǒng)做一些優(yōu)化趴泌,使得-Xss的值是可用的。

第五類內(nèi)存溢出錯(cuò)誤:

溢出關(guān)鍵字:

java.lang.OutOfMemoryError: unable to create new native thread

上面第四種溢出錯(cuò)誤拉庶,已經(jīng)說(shuō)明了線程的內(nèi)存空間嗜憔,其實(shí)線程基本只占用heap以外的內(nèi)存區(qū)域,也就是這個(gè)錯(cuò)誤說(shuō)明除了heap以外的區(qū)域氏仗,無(wú)法為線程分配一塊內(nèi)存區(qū)域了吉捶,這個(gè)要么是內(nèi)存本身就不夠,要么heap的空間設(shè)置得太大了皆尔,導(dǎo)致了剩余的內(nèi)存已經(jīng)不多了呐舔,而由于線程本身要占用內(nèi)存,所以就不夠用了慷蠕,說(shuō)明了原因珊拼,如何去修改,不用我多說(shuō)流炕,你懂的澎现。

第六類內(nèi)存溢出:

溢出關(guān)鍵字

java.lang.OutOfMemoryError: request {} byte for {}out of swap

這類錯(cuò)誤一般是由于地址空間不夠而導(dǎo)致仅胞。

六大類常見(jiàn)溢出已經(jīng)說(shuō)明JVM中99%的溢出情況,要逃出這些溢出情況非常困難剑辫,除非一些很怪異的故障問(wèn)題會(huì)發(fā)生干旧,比如由于物理內(nèi)存的硬件問(wèn)題,導(dǎo)致了code cache的錯(cuò)誤(在由byte code轉(zhuǎn)換為native code的過(guò)程中出現(xiàn)揭斧,但是概率極低)莱革,這種情況內(nèi)存 會(huì)被直接crash掉,類似還有swap的頻繁交互在部分系統(tǒng)中會(huì)導(dǎo)致系統(tǒng)直接被crash掉讹开,OS地址空間不夠的話盅视,系統(tǒng)根本無(wú)法啟動(dòng),呵呵旦万;JNI的濫用也會(huì)導(dǎo)致一些本地內(nèi)存無(wú)法釋放的問(wèn)題闹击,所以盡量避開(kāi)JNI;socket連接數(shù)據(jù)打開(kāi)過(guò)多的socket也會(huì)報(bào)類似:IOException: Too many open files等錯(cuò)誤信息成艘。

JNI就不用多說(shuō)了赏半,盡量少用,除非你的代碼太牛B了淆两,我無(wú)話可說(shuō)断箫,呵呵,這種內(nèi)存如果沒(méi)有在被調(diào)用的語(yǔ)言內(nèi)部將內(nèi)存釋放掉(如C語(yǔ)言)秋冰,那么在進(jìn)程結(jié)束前這些內(nèi)存永遠(yuǎn)釋放不掉仲义,解決辦法只有一個(gè)就是將進(jìn)程kill掉。

另外GC本身是需要內(nèi)存空間的剑勾,因?yàn)樵谶\(yùn)算和中間數(shù)據(jù)轉(zhuǎn)換過(guò)程中都需要有內(nèi)存埃撵,所以你要保證GC的時(shí)候有足夠的內(nèi)存哦,如果沒(méi)有的話GC的過(guò)程將會(huì)非常的緩慢虽另。

順便這里就提及一些新的CMS GC的內(nèi)容和策略(有點(diǎn)亂暂刘,每次寫(xiě)都很亂,但是能看多少看多少吧):

首先我再寫(xiě)一次一前博客中的已經(jīng)寫(xiě)過(guò)的內(nèi)容捂刺,就是很多參數(shù)沒(méi)啥建議值谣拣,建議值是自己在現(xiàn)場(chǎng)根據(jù)實(shí)際情況科學(xué)計(jì)算和測(cè)試得到的綜合效果,建議值沒(méi)有絕對(duì)好的族展,而且默認(rèn)值很多也是有問(wèn)題的芝发,因?yàn)椴煌陌姹竞蛷S商都有很大的區(qū)別,默認(rèn)值沒(méi)有永久都是一樣的苛谷,就像-Xss參數(shù)的變化一樣辅鲸,要看到你當(dāng)前的java程序heap的大致情況可以這樣看看(以下參數(shù)是隨便設(shè)置的,并不是什么默認(rèn)值):

$sudo jmap -heap pgrep java
Attaching to process ID 4280, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 19.1-b02

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 134217728 (128.0MB)
MaxNewSize = 134217728 (128.0MB)
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 134217728 (128.0MB)
MaxPermSize = 268435456 (256.0MB)

Heap Usage:
PS Young Generation
Eden Space:
capacity = 85721088 (81.75MB)
used = 22481312 (21.439849853515625MB)
free = 63239776 (60.310150146484375MB)
26.22611602876529% used
From Space:
capacity = 24051712 (22.9375MB)
used = 478488 (0.45632171630859375MB)
free = 23573224 (22.481178283691406MB)
1.9894134770946867% used
To Space:
capacity = 24248320 (23.125MB)
used = 0 (0.0MB)
free = 24248320 (23.125MB)
0.0% used
PS Old Generation
capacity = 939524096 (896.0MB)
used = 16343864 (15.586723327636719MB)
free = 923180232 (880.4132766723633MB)
1.7395896571023124% used
PS Perm Generation
capacity = 134217728 (128.0MB)
used = 48021344 (45.796722412109375MB)
free = 86196384 (82.20327758789062MB)
35.77868938446045% used

付:sudo是需要拿到管理員權(quán)限腹殿,如果你的系統(tǒng)權(quán)限很大那么就不需要了独悴,最后的grep java那個(gè)內(nèi)容如果不對(duì)例书,可以直接通過(guò)jps或者ps命令將和java相關(guān)的進(jìn)程號(hào)直接寫(xiě)進(jìn)去,如:java -map 4280刻炒,這個(gè)參數(shù)其實(shí)完全可以通過(guò)jstat工具來(lái)替代决采,而且看到的效果更加好,這個(gè)參數(shù)在線上應(yīng)用中坟奥,盡量少用(尤其是高并發(fā)的應(yīng)用中)树瞭,可能會(huì)觸發(fā)JVM的bug,導(dǎo)致應(yīng)用掛起爱谁;在jvm 1.6u14后可以編寫(xiě)任意一段程序晒喷,然后在運(yùn)行程序的時(shí)候,增加參數(shù)為:-XX:+PrintFlagsFinal來(lái)輸出當(dāng)前JVM中運(yùn)行時(shí)的參數(shù)值访敌,或者通過(guò)jinfo來(lái)查看凉敲,jinfo是非常強(qiáng)大的工具,可以對(duì)部分參數(shù)進(jìn)行動(dòng)態(tài)修改寺旺,當(dāng)然內(nèi)存相關(guān)的東西是不能修改的爷抓,只能增加一些不是很相關(guān)的參數(shù),有關(guān)JVM的工具使用阻塑,后續(xù)文章中如果有機(jī)會(huì)我們?cè)賮?lái)探討蓝撇,不是本文的重點(diǎn);補(bǔ)充:關(guān)于參數(shù)的默認(rèn)值對(duì)不同的JVM版本陈莽、不同的廠商唉地、運(yùn)行于不同的環(huán)境(一般和位數(shù)有關(guān)系)默認(rèn)值會(huì)有區(qū)別。

OK传透,再說(shuō)下反復(fù)的一句,沒(méi)有必要的話就不要亂設(shè)置參數(shù)极颓,參數(shù)不是拿來(lái)玩的朱盐,默認(rèn)的參數(shù)對(duì)于這門JDK都是有好處的,關(guān)鍵是否適合你的應(yīng)用場(chǎng)景菠隆,一般來(lái)講你常規(guī)的只需要設(shè)置以下幾個(gè)參數(shù)就可以了:

-server 表示為服務(wù)器端兵琳,會(huì)提供很多服務(wù)器端默認(rèn)的配置,如并行回收骇径,而服務(wù)器上一般這個(gè)參數(shù)都是默認(rèn)的,所以都是可以省掉,與之對(duì)應(yīng)的還有一個(gè)-client參數(shù)膘侮,一般在64位機(jī)器上阳惹,JVM是默認(rèn)啟動(dòng)-server參數(shù),也就是默認(rèn)啟動(dòng)并行GC的晰筛,但是是ParallelGC而不是ParallelOldGC嫡丙,兩者算法不同(后面會(huì)簡(jiǎn)單說(shuō)明下)拴袭,而比較特殊的是windows 32位上默認(rèn)是-client,這兩個(gè)的區(qū)別不僅僅是默認(rèn)的參數(shù)不一樣曙博,在jdk包下的jre包下一般會(huì)包含client和server包拥刻,下面分別對(duì)應(yīng)啟動(dòng)的動(dòng)態(tài)鏈接庫(kù),而真正看到的java父泳、javac等相關(guān)命令指示一個(gè)啟動(dòng)導(dǎo)向般哼,它只是根據(jù)命令找到對(duì)應(yīng)的JVM并傳入jvm中進(jìn)行啟動(dòng),也就是看到的java.exe這些文件并不是jvm惠窄;說(shuō)了這么多蒸眠,最終總結(jié)一下就是,-server和-client就是完全不同的兩套VM睬捶,一個(gè)用于桌面應(yīng)用黔宛,一個(gè)用于服務(wù)器的。

-Xmx 為Heap區(qū)域的最大值

-Xms 為Heap區(qū)域的初始值擒贸,線上環(huán)境需要與-Xmx設(shè)置為一致臀晃,否則capacity的值會(huì)來(lái)回飄動(dòng),飄得你心曠神怡介劫,你懂的徽惋。

-Xss(或-ss) 這個(gè)其實(shí)也是可以默認(rèn)的,如果你真的覺(jué)得有設(shè)置的必要座韵,你就改下吧险绘,1.5以后是1M的默認(rèn)大小(指一個(gè)線程的native空間)誉碴,如果代碼不多宦棺,可以設(shè)置小點(diǎn)來(lái)讓系統(tǒng)可以接受更大的內(nèi)存。注意黔帕,還有一個(gè)參數(shù)是-XX:ThreadStackSize代咸,這兩個(gè)參數(shù)在設(shè)置的過(guò)程中如果都設(shè)置是有沖突的,一般按照J(rèn)VM常理來(lái)說(shuō)成黄,誰(shuí)設(shè)置在后面呐芥,就以誰(shuí)為主,但是最后發(fā)現(xiàn)如果是在1.6以上的版本奋岁,-Xss設(shè)置在后面的確都是以-Xss為主思瘟,但是要是-XX:ThreadStackSize設(shè)置在后面,主線程還是為-Xss為主闻伶,而其它線程以-XX:ThreadStackSize為主滨攻,主線程做了一個(gè)特殊判定處理;單獨(dú)設(shè)置都是以本身為主,-Xss不設(shè)置也不會(huì)采用其默認(rèn)值铡买,除非兩個(gè)都不設(shè)置會(huì)采用-Xss的默認(rèn)值更鲁。另外這個(gè)參數(shù)針對(duì)于hotspot的vm,在IBM的jvm中奇钞,還有一個(gè)參數(shù)為-Xoss澡为,主要原因是IBM在對(duì)棧的處理上有操作數(shù)棧和方法棧等各種不同的棧種類,而hotspot不管是什么棧都放在一個(gè)私有的線程內(nèi)部的景埃,不區(qū)分是什么棧媒至,所以只需要設(shè)置一個(gè)參數(shù),而IBM的J9不是這樣的谷徙;有關(guān)棧上的細(xì)節(jié)拒啰,后續(xù)我們有機(jī)會(huì)專門寫(xiě)文章來(lái)說(shuō)明。

-XX:PermSize與-XX:MaxPermSize兩個(gè)包含了class的裝載的位置完慧,或者說(shuō)是方法區(qū)(但不是本地方法區(qū))谋旦,在Hotspot默認(rèn)情況下為64M,主意全世界的JVM只有hostpot的VM才有Perm的區(qū)域屈尼,或者說(shuō)只有hotspot才有對(duì)用戶可以設(shè)置的這塊區(qū)域册着,其他的JVM都沒(méi)有,其實(shí)并不是沒(méi)有這塊區(qū)域脾歧,而是這塊區(qū)域沒(méi)有讓用戶來(lái)設(shè)置甲捏,其實(shí)這塊區(qū)域本身也不應(yīng)該讓用戶來(lái)設(shè)置,我們也沒(méi)有一個(gè)明確的說(shuō)法這塊空間必須要設(shè)置多大鞭执,都是拍腦袋設(shè)置一個(gè)數(shù)字司顿,如果發(fā)布到線上看下如果用得比較多,就再多點(diǎn)兄纺,如果用的少大溜,就減少點(diǎn),而這塊區(qū)域和性能關(guān)鍵沒(méi)有多大關(guān)系估脆,只要能裝下就OK钦奋,并且時(shí)不時(shí)會(huì)因?yàn)镻erm不夠而導(dǎo)致Full GC,所以交給開(kāi)發(fā)者來(lái)調(diào)節(jié)這個(gè)參數(shù)不知道是怎么想的旁蔼;所以O(shè)racle將在新一代JVM中將這個(gè)區(qū)域徹底刪掉,也就是對(duì)用戶透明疙教,G1的如果真正穩(wěn)定起來(lái)棺聊,以后JVM的啟動(dòng)參數(shù)將會(huì)非常簡(jiǎn)單,而且理論上管理再大的內(nèi)存也是沒(méi)有問(wèn)題的贞谓,其實(shí)G1(garbage first限佩,一種基于region的垃圾收集回收器)已經(jīng)在hotspot中開(kāi)始有所試用,不過(guò)目前效果不好,還不如CMS呢祟同,所以只是試用作喘,G1已經(jīng)作為ORACLE對(duì)JVM研發(fā)的最高重點(diǎn),CMS自現(xiàn)在最高版本后也不再有新功能(可以修改bug)晕城,該項(xiàng)目已經(jīng)進(jìn)行5年泞坦,尚未發(fā)布正式版,CMS是四五年前發(fā)布的正式版砖顷,但是是最近一兩年才開(kāi)始穩(wěn)定贰锁,而G1的復(fù)雜性將會(huì)遠(yuǎn)遠(yuǎn)超越CMS,所以要真正使用上G1還有待考察滤蝠,全世界目前只有IBM J9真正實(shí)現(xiàn)了G1論文中提到的思想(論文于05年左右發(fā)表)豌熄,IBM已經(jīng)將J9應(yīng)用于websphere中,但是并不代表這是全世界最好的jvm物咳,全世界最好的jvm是Azul(無(wú)停頓垃圾回收算法和一個(gè)零開(kāi)銷的診斷/監(jiān)控工具)锣险,幾乎可以說(shuō)這個(gè)jvm是沒(méi)有暫停的,在全世界很多頂尖級(jí)的公司使用览闰,不過(guò)價(jià)格非常貴芯肤,不能直接使用,目前這個(gè)jvm的主導(dǎo)者在研究JRockit焕济,而目前hotspot和JRockit都是Oracle的纷妆,所以他們可能會(huì)合并,所以我們應(yīng)該對(duì)JVM的性能充滿信心晴弃。

也就是說(shuō)你常用的情況下只需要設(shè)置4個(gè)參數(shù)就OK了掩幢,除非你的應(yīng)用有些特殊,否則不要亂改上鞠,那么來(lái)看看一些其他情況的參數(shù)吧:

先來(lái)看個(gè)不大常用的际邻,就是大家都知道JVM新的對(duì)象應(yīng)該說(shuō)幾乎百分百的在Eden里面,除非Eden真的裝不下芍阎,我們不考慮這種變態(tài)的問(wèn)題世曾,因?yàn)榫€上環(huán)境Eden區(qū)域都是不小的,來(lái)降低GC的次數(shù)以及全局 GC的概率谴咸;而JVM習(xí)慣將內(nèi)存按照較為連續(xù)的位置進(jìn)行分配轮听,這樣使得有足夠的內(nèi)存可以被分配,減少碎片岭佳,那么對(duì)于內(nèi)存最后一個(gè)位置必然就有大量的征用問(wèn)題血巍,JVM在高一點(diǎn)的版本里面提出了為每個(gè)線程分配一些私有的區(qū)域來(lái)做來(lái)解決這個(gè)問(wèn)題,而1.5后的版本還可以動(dòng)態(tài)管理這些區(qū)域珊随,那么如何自己設(shè)置和查看這些區(qū)域呢述寡,看下英文全稱為:Thread Local Allocation Buffer柿隙,簡(jiǎn)稱就是:TLAB,即內(nèi)存本地的持有的buffer鲫凶,設(shè)置參數(shù)有:

-XX:+UseTLAB 啟用這種機(jī)制的意思
-XX:TLABSize=<size in kb> 設(shè)置大小禀崖,也就是本地線程中的私有區(qū)域大小(只有這個(gè)區(qū)域放不下才會(huì)到Eden中去申請(qǐng))螟炫。
-XX:+ResizeTLAB 是否啟動(dòng)動(dòng)態(tài)修改

這幾個(gè)參數(shù)在多CPU下非常有用波附。

-XX:+PrintTLAB 可以輸出TLAB的內(nèi)容。

下面再閑扯些其它的參數(shù):

如果你需要對(duì)Yong區(qū)域進(jìn)行并行回收應(yīng)該如何修改呢不恭?在jdk1.5以后可以使用參數(shù):

-XX:+UseParNewGC

注意: 與它沖突的參數(shù)是:-XX:+UseParallelOldGC和-XX:+UseSerialGC叶雹,如果需要用這個(gè)參數(shù),又想讓整個(gè)區(qū)域是并行回收的换吧,那么就使用-XX:+UseConcMarkSweepGC參數(shù)來(lái)配合折晦,其實(shí)這個(gè)參數(shù)在使用了CMS后,默認(rèn)就會(huì)啟動(dòng)該參數(shù)沾瓦,也就是這個(gè)參數(shù)在CMS GC下是無(wú)需設(shè)置的满着,后面會(huì)提及到這些參數(shù)。

默認(rèn)服務(wù)器上的對(duì)Full并行GC策略為(這個(gè)時(shí)候Yong空間回收的時(shí)候啟動(dòng)PSYong算法贯莺,也是并行回收的):

-XX:+UseParallelGC

另外风喇,在jdk1.5后出現(xiàn)一個(gè)新的參數(shù)如下,這個(gè)對(duì)Yong的回收算法和上面一樣缕探,對(duì)Old區(qū)域會(huì)有所區(qū)別魂莫,上面對(duì)Old回收的過(guò)程中會(huì)做一個(gè)全局的Compact,也就是全局的壓縮操作爹耗,而下面的算法是局部壓縮耙考,為什么要局部壓縮呢?是因?yàn)镴VM發(fā)現(xiàn)每次壓縮后再邏輯上數(shù)據(jù)都在Old區(qū)域的左邊位置潭兽,申請(qǐng)的時(shí)候從左向右申請(qǐng)倦始,那么生命力越長(zhǎng)的對(duì)象就一般是靠左的,所以它認(rèn)為左邊的對(duì)象就是生命力很強(qiáng)山卦,而且較為密集的鞋邑,所以它針對(duì)這種情況進(jìn)行部分密集,但是這兩種算法mark階段都是會(huì)暫停的账蓉,而且存活的對(duì)象越多活著的越多枚碗;而ParallelOldGC會(huì)進(jìn)行部分壓縮算法(主意一點(diǎn),最原始的copy算法是不需要經(jīng)過(guò)mark階段铸本,因?yàn)橹恍枰业揭粋€(gè)或活著的就只需要做拷貝就可以肮雨,而Yong區(qū)域借用了Copy算法,只是唯一的區(qū)別就是傳統(tǒng)的copy算法是采用兩個(gè)相同大小的內(nèi)存來(lái)拷貝归敬,浪費(fèi)空間為50%酷含,所以分代的目標(biāo)就是想要實(shí)現(xiàn)很多優(yōu)勢(shì)所在,認(rèn)為新生代85%以上的對(duì)象都應(yīng)該是死掉的汪茧,所以S0和S1一般并不是很大)椅亚,該算法為jdk 1.5以后對(duì)于絕大部分應(yīng)用的最佳選擇。

-XX:+UseParallelOldGC

-XX:ParallelGCThread=12:并行回收的線程數(shù)舱污,最好根據(jù)實(shí)際情況而定呀舔,因?yàn)榫€程多往往存在征用調(diào)度和上下文切換的開(kāi)銷;而且也并非CPU越多線程數(shù)也可以設(shè)置越大扩灯,一般設(shè)置為12就再增加用處也不大媚赖,主要是算法本身內(nèi)部的征用會(huì)導(dǎo)致其線程的極限就是這樣。

設(shè)置Yong區(qū)域大兄椴濉:

-Xmn Yong區(qū)域的初始值和最大值一樣大

-XX:NewSize和-XX:MaxNewSize如果設(shè)置以為一樣大就是和-Xmn惧磺,在JRockit中會(huì)動(dòng)態(tài)變化這些參數(shù)捻撑,根據(jù)實(shí)際情況有可能會(huì)變化出兩個(gè)Yong區(qū)域,或者沒(méi)有Yong區(qū)域番捂,有些時(shí)候會(huì)生出來(lái)一個(gè)半長(zhǎng)命對(duì)象區(qū)域;這里除了這幾個(gè)參數(shù)外江解,還有一個(gè)參數(shù)是NewRatio是設(shè)置Old/Yong的倍數(shù)的,這幾個(gè)參數(shù)都是有沖突的鳖枕,服務(wù)器端建議是設(shè)置-Xmn就可以了,如果幾個(gè)參數(shù)全部都有設(shè)置呼股,-Xmn和-XX:NewSize與-XX:MaxNewSize將是誰(shuí)設(shè)置在后面,以誰(shuí)的為準(zhǔn)彭谁,而-XX:NewSize -XX:MaxNewSize與-XX:NewRatio時(shí)缠局,那么參數(shù)設(shè)置的結(jié)果可能會(huì)以下這樣的(jdk 1.4.1后):

min(MaxNewSize,max(NewSize, heap/(NewRatio+1)))

-XX:NewRatio為Old區(qū)域?yàn)閅ong的多少倍狭园,間接設(shè)置Yong的大小,1.6中如果使用此參數(shù)罚舱,則默認(rèn)會(huì)在適當(dāng)時(shí)候被動(dòng)態(tài)調(diào)整管闷,具體請(qǐng)看下面參數(shù)UseAdaptiveSizepollcy 的說(shuō)明包个。

三個(gè)參數(shù)不要同時(shí)設(shè)置,因?yàn)槎际窃O(shè)置Yong的大小的树灶。

-XX:SurvivorRatio:該參數(shù)為Eden與兩個(gè)求助空間之一的比例天通,注意Yong的大小等價(jià)于Eden + S0 + S1熄驼,S0和S1的大小是等價(jià)的谜洽,這個(gè)參數(shù)為Eden與其中一個(gè)S區(qū)域的大小比例阐虚,如參數(shù)為8实束,那么Eden就占用Yong的80%,而S0和S1分別占用10%构订。

以前的老版本有一個(gè)參數(shù)為:-XX:InitialSurivivorRatio悼瘾,如果不做任何設(shè)置亥宿,就會(huì)以這個(gè)參數(shù)為準(zhǔn)烫扼,這個(gè)參數(shù)的默認(rèn)值就是8碍庵,不過(guò)這個(gè)參數(shù)并不是Eden/Survivor的大小,而是Yong/Survivor芽淡,所以所以默認(rèn)值8,代表每一個(gè)S區(qū)域的空間大小為Yong區(qū)域的12.5%而不是10%掷邦。另外順便提及一下抚岗,每次大家看到GC日志的時(shí)候哪怔,GC日志中的每個(gè)區(qū)域的最大值认境,其中Yong的空間最大值叉信,始終比設(shè)置的Yong空間的大小要小一點(diǎn)硼身,大概是小12.5%左右佳遂,那是因?yàn)槊看慰捎每臻g為Eden加上一個(gè)Survivor區(qū)域的大小,而不是整個(gè)Yong的大小荚板,因?yàn)榭捎每臻g每次最多是這樣大啸驯,兩個(gè)Survivor區(qū)域始終有一塊是空的罚斗,所以不會(huì)加上兩個(gè)來(lái)計(jì)算针姿。

-XX:MaxTenuringThreshold=15:在正常情況下距淫,新申請(qǐng)的對(duì)象在Yong區(qū)域發(fā)生多少次GC后就會(huì)被移動(dòng)到Old(非正常就是S0或S1放不下或者不太可能出現(xiàn)的Eden都放不下的對(duì)象)榕暇,這個(gè)參數(shù)一般不會(huì)超過(guò)16(因?yàn)橛?jì)數(shù)器從0開(kāi)始計(jì)數(shù),所以設(shè)置為15的時(shí)候相當(dāng)于生命周期為16)狰晚。

要查看現(xiàn)在的這個(gè)值的具體情況壁晒,可以使用參數(shù):-XX:+PrintTenuringDistribution

通過(guò)上面的jmap應(yīng)該可以看出我的機(jī)器上的MinHeapFreeRatio和MaxHeapFreeRatio分別為40個(gè)70秒咐,也就是大家經(jīng)常說(shuō)的在GC后剩余空間小于40%時(shí)capacity開(kāi)始增大携取,而大于70%時(shí)減小歹茶,由于我們不希望讓它移動(dòng)惊豺,所以這兩個(gè)參數(shù)幾乎沒(méi)有意義尸昧,如果你需要設(shè)置就設(shè)置參數(shù)為:

-XX:MinHeapFreeRatio=40
-XX:MaxHeapFreeRatio=70

JDK 1.6后有一個(gè)動(dòng)態(tài)調(diào)節(jié)板塊的烹俗,當(dāng)然如果你的每一個(gè)板塊都是設(shè)置固定值幢妄,這個(gè)參數(shù)也沒(méi)有用茫负,不過(guò)如果是非固定的,建議還是不要?jiǎng)討B(tài)調(diào)整榕吼,默認(rèn)是開(kāi)啟的羹蚣,建議將其關(guān)掉顽素,參數(shù)為:

-XX:+UseAdaptiveSizepollcy 建議使用-XX:-UseAdaptiveSizepollcy關(guān)掉胁出,為什么當(dāng)你的參數(shù)設(shè)置了NewRatio、Survivor戚哎、MaxTenuringThreshold這幾個(gè)參數(shù)如果在啟動(dòng)了動(dòng)態(tài)更新情況下型凳,是無(wú)效的甘畅,當(dāng)然如果你設(shè)置-Xmn是有效的疏唾,但是如果設(shè)置的比例的話槐脏,初始化可能會(huì)按照你的參數(shù)去運(yùn)行顿天,不過(guò)運(yùn)行過(guò)程中會(huì)通過(guò)一定的算法動(dòng)態(tài)修改蔑担,監(jiān)控中你可能會(huì)發(fā)現(xiàn)這些參數(shù)會(huì)發(fā)生改變啤握,甚至于S0和S1的大小不一樣排抬。

如果啟動(dòng)了這個(gè)參數(shù),又想要跟蹤變化畴蒲,那么就使用參數(shù):-XX:+PrintAdaptiveSizePolicy

上面已經(jīng)提到模燥,javaNIO中通過(guò)Direct內(nèi)存來(lái)提高性能蔫骂,這個(gè)區(qū)域的大小默認(rèn)是64M辽旋,在適當(dāng)?shù)膱?chǎng)景可以設(shè)置大一些补胚。

-XX:MaxDirectMemorySize

一個(gè)不太常用的參數(shù):

-XX:+ScavengeBeforeFullGC 默認(rèn)是開(kāi)啟狀態(tài)溶其,在full GC前先進(jìn)行minor GC瓶逃。

對(duì)于java堆中如果要設(shè)置大頁(yè)內(nèi)存厢绝,可以通過(guò)設(shè)置參數(shù):

付:此參數(shù)必須在操作系統(tǒng)的內(nèi)核支持的基礎(chǔ)上代芜,需要在OS級(jí)別做操作為:

echo 1024 > /proc/sys/vm/nr_hugepages

echo 2147483647 > /proc/sys/kernel/shmmax

-XX:+UseLargePages

-XX:LargePageSizeInBytes

此時(shí)整個(gè)JVM都將在這塊內(nèi)存中,否則全部不在這塊內(nèi)存中嫡秕。

javaIO的臨時(shí)目錄設(shè)置

-Djava.io.tmpdir

jstack會(huì)去尋找/tmp/hsperfdata_admin下去尋找與進(jìn)程號(hào)相同的文件昆咽,32位機(jī)器上是沒(méi)有問(wèn)題的掷酗,64為機(jī)器的是有BUG的泻轰,在jdk 1.6u23版本中已經(jīng)修復(fù)了這個(gè)bug浮声,如果你遇到這個(gè)問(wèn)題泳挥,就需要升級(jí)JDK了屉符。

還記得上次說(shuō)的平均晉升大小嗎矗钟,在并行GC時(shí)真仲,如果平均晉升大小大于old剩余空間秸应,則發(fā)生full GC软啼,那么當(dāng)小于剩余空間時(shí)祸挪,也就是平均晉升小于剩余空間贿条,但是剩余空間小于eden + 一個(gè)survivor的空間時(shí)整以,此時(shí)就依賴于參數(shù):

-XX:-HandlePromotionFailure

啟動(dòng)該參數(shù)時(shí)公黑,上述情況成立就發(fā)生minor gc(YGC)凡蚜,大于則發(fā)生full gc(major gc)恶迈。

一般默認(rèn)直接分配的對(duì)象如果大于Eden的一半就會(huì)直接晉升到old區(qū)域蝉绷,但是也可以通過(guò)參數(shù)來(lái)指定:

-XX:PretenureSizeThreshold=2m 我個(gè)人不建議使用這個(gè)參數(shù)

也就是當(dāng)申請(qǐng)對(duì)象大于這個(gè)值就會(huì)晉升到old區(qū)域熔吗。

傳說(shuō)中GC時(shí)間的限制桅狠,一個(gè)是通過(guò)比例限制中跌,一個(gè)是通過(guò)最大暫停時(shí)間限制漩符,但是GC時(shí)間能限制么嗜暴,呵呵,在增量中貌似可以限制咐容,不過(guò)不能限制住GC總體的時(shí)間戳粒,所以這個(gè)參數(shù)也不是那么關(guān)鍵奄妨。

-XX:GCTimeRatio=

-XX:MaxGCPauseMillis

-XX:GCTimeLimit

要看到真正暫停的時(shí)間就一個(gè)是看GCDetail的日志展蒂,另一個(gè)是設(shè)置參數(shù)看:

-XX:+PrintGCApplicationStoppedTime

有些人锰悼,有些人就是喜歡在代碼里面里頭寫(xiě)System.gc()箕般,怂坷铮酷臼婆,這個(gè)不是測(cè)試程序是線上業(yè)務(wù)颁褂,這樣將會(huì)導(dǎo)致N多的問(wèn)題颁独,不多說(shuō)了誓酒,你應(yīng)該懂的靠柑,不懂的話看下書(shū)吧捣染,而RMI是很不聽(tīng)話的一個(gè)鳥(niǎo)玩意耍攘,EJB的框架也是基于RMI寫(xiě)的蕾各,RMI為什么不聽(tīng)話呢式曲,就是它自己在里面非要搞個(gè)System.gc()兰伤,哎敦腔,為了放置頻繁的做符衔,頻繁的做判族,你就將這個(gè)命令的執(zhí)行禁用掉吧颗品,當(dāng)然程序不用改躯枢,不然那些EJB都跑步起來(lái)了锄蹂,呵呵:

-XX:+DisableExplicitGC 默認(rèn)是沒(méi)有禁用掉得糜,寫(xiě)成+就是禁用掉的了,但是有些時(shí)候在使用allocateDirect的時(shí)候治宣,很多時(shí)候還真需要System.gc來(lái)強(qiáng)制回收這塊資源侮邀。

內(nèi)存溢出時(shí)導(dǎo)出溢出的錯(cuò)誤信息:
-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/home/xieyu/logs/ 這個(gè)參數(shù)指定導(dǎo)出時(shí)的路徑,不然導(dǎo)出的路徑就是虛擬機(jī)的目標(biāo)位置华畏,不好找了,默認(rèn)的文件名是:java_pid<進(jìn)程號(hào)>.hprof亡笑,這個(gè)文件可以類似使用jmap -dump:file=....,format=b <pid>來(lái)dump類似的內(nèi)容拼岳,文件后綴都是hprof,然后下載mat工具進(jìn)行分析即可(不過(guò)內(nèi)存有多大dump文件就多大况芒,而本地分析的時(shí)候內(nèi)存也需要那么大惜纸,所以很多時(shí)候下載到本地都無(wú)法啟動(dòng)是很正常的),后續(xù)文章有機(jī)會(huì)我們來(lái)說(shuō)明這些工具绝骚,另外jmap -dump參數(shù)也不要經(jīng)常用,會(huì)導(dǎo)致應(yīng)用掛起哦;另外此參數(shù)只會(huì)在第一次輸出OOM的時(shí)候才會(huì)進(jìn)行堆的dump操作(java heap的溢出是可以繼續(xù)運(yùn)行再運(yùn)行的程序的压汪,至于web應(yīng)用是否服務(wù)要看應(yīng)用服務(wù)器自身如何處理粪牲,而c heap區(qū)域的溢出就根本沒(méi)有dump的機(jī)會(huì),因?yàn)橹苯泳湾礄C(jī)了止剖,目前系統(tǒng)無(wú)法看到c heap的大小以及內(nèi)部變化腺阳,要看大小只能間接通過(guò)看JVM進(jìn)程的內(nèi)存大小(top或類似參數(shù))穿香,這個(gè)大小一般會(huì)大于heap+perm的大小亭引,多余的部分基本就可以認(rèn)為是c heap的大小了,而看內(nèi)部變化呢只有g(shù)oogle perftools可以達(dá)到這個(gè)目的)皮获,如果內(nèi)存過(guò)大這個(gè)dump操作將會(huì)非常長(zhǎng)焙蚓,所以hotspot如果以后想管理大內(nèi)存,這塊必須有新的辦法出來(lái)洒宝。

最后购公,用dump出來(lái)的文件,通過(guò)mat分析出來(lái)的結(jié)果往往有些時(shí)候難以直接確定到底哪里有問(wèn)題雁歌,可以看到的維度大概有:那個(gè)類使用的內(nèi)存最多宏浩,以及每一個(gè)線程使用的內(nèi)存,以及線程內(nèi)部每一個(gè)調(diào)用的類和方法所使用的內(nèi)存靠瞎,但是很多時(shí)候無(wú)法判定到底是程序什么地方調(diào)用了這個(gè)類或者方法比庄,因?yàn)檫@里只能看到最終消耗內(nèi)存的類,但是不知道誰(shuí)使用了它较坛,一個(gè)辦法是掃描代碼印蔗,但是太笨重扒最,而且如果是jar包中調(diào)用了就不好弄了丑勤,另一種方法是寫(xiě)agent,那么就需要相應(yīng)的配合了吧趣,但是有一個(gè)非常好的工具就是btrace工具(jdk 1.7貌似還不支持)法竞,可以跟蹤到某個(gè)類的某個(gè)方法被那些類中的方法調(diào)用過(guò)耙厚,那這個(gè)問(wèn)題就好說(shuō)了,只要知道開(kāi)銷內(nèi)存的是哪一個(gè)類岔霸,就能知道誰(shuí)調(diào)用過(guò)它薛躬,OK,關(guān)于btrace的不是本文重點(diǎn)呆细,網(wǎng)上都有型宝,后續(xù)文章有機(jī)會(huì)再探討,
原理:
No performance impact during runtime(無(wú)性能影響)
Dumping a –Xmx512m heap
Create a 512MB .hprof file(512M內(nèi)存就dump出512M的空間大行跻)
JVM is “dead” during dumping(死掉時(shí)dump)
Restarting JVM during this dump will cause unusable .hprof file(重啟導(dǎo)致文件不可用)

注明的NUMA架構(gòu)趴酣,在JVM中開(kāi)始支持,當(dāng)然也需要CPU和OS的支持才可以坑夯,需要設(shè)置參數(shù)為:

-XX:+UseNUMA 必須在并行GC的基礎(chǔ)上才有的

老年代無(wú)法分配區(qū)域的最大等待時(shí)間為(默認(rèn)值為0岖寞,但是也不要去動(dòng)它):

-XX:GCExpandToAllocateDelayMillis

讓JVM中所有的set和get方法轉(zhuǎn)換為本地代碼:

-XX:+UseFastAccessorMethods

以時(shí)間戳輸出Heap的利用率

-XX:+PrintHeapUsageOverTime

在64bit的OS上面(其實(shí)一般達(dá)不到57位左右),由于指針會(huì)放大為8個(gè)byte柜蜈,所以會(huì)導(dǎo)致空間使用增加仗谆,當(dāng)然,如果內(nèi)存夠大淑履,就沒(méi)有問(wèn)題隶垮,但是如果升級(jí)到64bit系統(tǒng)后,只是想讓內(nèi)存達(dá)到4G或者8G秘噪,那么就完全可以通過(guò)很多指針壓縮為4byte就OK了岁疼,所以在提供以下參數(shù)(本參數(shù)于jdk 1.6u23后使用,并自動(dòng)開(kāi)啟缆娃,所以也不需要你設(shè)置捷绒,知道就OK):

-XX:+UseCompressedOops 請(qǐng)注意:這個(gè)參數(shù)默認(rèn)在64bit的環(huán)境下默認(rèn)啟動(dòng),但是如果JVM的內(nèi)存達(dá)到32G后贯要,這個(gè)參數(shù)就會(huì)默認(rèn)為不啟動(dòng)暖侨,因?yàn)?2G內(nèi)存后,壓縮就沒(méi)有多大必要了崇渗,要管理那么大的內(nèi)存指針也需要很大的寬度了字逗。

后臺(tái)JIT編譯優(yōu)化啟動(dòng)

-XX:+BackgroundCompilation

如果你要輸出GC的日志以及時(shí)間戳,相關(guān)的參數(shù)有:

-XX:+PrintGCDetails 輸出GC的日志詳情宅广,包含了時(shí)間戳

-XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳信息葫掉,按照啟動(dòng)JVM后相對(duì)時(shí)間的每次GC的相對(duì)秒值(毫秒在小數(shù)點(diǎn)后面),也就是每次GC相對(duì)啟動(dòng)JVM啟動(dòng)了多少秒后發(fā)生了這次GC

-XX:+PrintGCDateStamps輸出GC的時(shí)間信息跟狱,會(huì)按照系統(tǒng)格式的日期輸出每次GC的時(shí)間

-XX:+PrintGCTaskTimeStamps輸出任務(wù)的時(shí)間戳信息俭厚,這個(gè)細(xì)節(jié)上比較復(fù)雜,后續(xù)有文章來(lái)探討驶臊。

-XX:-TraceClassLoading 跟蹤類的裝載

-XX:-TraceClassUnloading 跟蹤類的卸載

-XX:+PrintHeapAtGC 輸出GC后各個(gè)堆板塊的大小挪挤。

將常量信息GC信息輸出到日志文件:

-Xloggc:/home/xieyu/logs/gc.log

現(xiàn)在面對(duì)大內(nèi)存比較流行是是CMS GC(最少1.5才支持)叼丑,首先明白CMS的全稱是什么,不是傳統(tǒng)意義上的內(nèi)容管理系統(tǒng)(Content Management System)哈扛门,第一次我也沒(méi)看懂鸠信,它的全稱是:Concurrent Mark Sweep,三個(gè)單詞分別代表并發(fā)论寨、標(biāo)記星立、清掃(主意這里沒(méi)有compact操作,其實(shí)CMS GC的確沒(méi)有compact操作)葬凳,也就是在程序運(yùn)行的同時(shí)進(jìn)行標(biāo)記和清掃工作贞铣,至于它的原理前面有提及過(guò),只是有不同的廠商在上面做了一些特殊的優(yōu)化沮明,比如一些廠商在標(biāo)記根節(jié)點(diǎn)的過(guò)程中辕坝,標(biāo)記完當(dāng)前的根,那么這個(gè)根下面的內(nèi)容就不會(huì)被暫图鼋。恢復(fù)運(yùn)行了酱畅,而移動(dòng)過(guò)程中,通過(guò)讀屏障來(lái)看這個(gè)內(nèi)存是不是發(fā)生移動(dòng)江场,如果在移動(dòng)稍微停一下纺酸,移動(dòng)過(guò)去后再使用,hotspot還沒(méi)這么厲害址否,暫停時(shí)間還是挺長(zhǎng)的餐蔬,只是相對(duì)其他的GC策略在面對(duì)大內(nèi)存來(lái)講是不錯(cuò)的選擇。

下面看一些CMS的策略(并發(fā)GC總時(shí)間會(huì)比常規(guī)的并行GC長(zhǎng)佑附,因?yàn)樗窃谶\(yùn)行時(shí)去做GC樊诺,很多資源征用都會(huì)影響其GC的效率,而總體的暫停時(shí)間會(huì)短暫很多很多音同,其并行線程數(shù)默認(rèn)為:(上面設(shè)置的并行線程數(shù) + 3)/ 4

付:CMS是目前Hotspot管理大內(nèi)存最好的JVM词爬,如果是常規(guī)的JVM,最佳選擇為ParallelOldGC权均,如果必須要以響應(yīng)時(shí)間為準(zhǔn)顿膨,則選擇CMS,不過(guò)CMS有兩個(gè)隱藏的隱患:

1叽赊、CMS GC雖然是并發(fā)且并行運(yùn)行的GC恋沃,但是初始化的時(shí)候如果采用默認(rèn)值92%(JVM 1.5的白皮書(shū)上描述為68%其實(shí)是錯(cuò)誤的,1.6是正確的)必指,就很容易出現(xiàn)問(wèn)題囊咏,因?yàn)镃MS GC僅僅針對(duì)Old區(qū)域,Yong區(qū)域使用ParNew算法,也就是Old的CMS回收和Yong的回收可以同時(shí)進(jìn)行匆笤,也就是回收過(guò)程中Yong有可能會(huì)晉升對(duì)象Old研侣,并且業(yè)務(wù)也可以同時(shí)運(yùn)行谱邪,所以92%基本開(kāi)始啟動(dòng)CMS GC很有可能old的內(nèi)存就不夠用了炮捧,當(dāng)內(nèi)存不夠用的時(shí)候,就啟動(dòng)Full GC惦银,并且這個(gè)Full GC是串行的咆课,所以如果弄的不好,CMS會(huì)比并行GC更加慢扯俱,為什么要啟用串行是因?yàn)镃MS GC书蚪、并行GC、串行GC的繼承關(guān)系決定的迅栅,簡(jiǎn)單說(shuō)就是它沒(méi)辦法去調(diào)用并行GC的代碼殊校,細(xì)節(jié)說(shuō)后續(xù)有文章來(lái)細(xì)節(jié)說(shuō)明),建議這個(gè)值設(shè)置為70%左右吧读存,不過(guò)具體時(shí)間還是自己決定为流。

2、CMS GC另一個(gè)大的隱患让簿,其實(shí)不看也差不多應(yīng)該清楚敬察,看名字就知道,就是不會(huì)做Compact操作尔当,它最惡心的地方也在這里莲祸,所以上面才說(shuō)一般的應(yīng)用都不使用它,它只有內(nèi)存垃圾非常多椭迎,多得無(wú)法分配晉升的空間的時(shí)候才會(huì)出現(xiàn)一次compact锐帜,但是這個(gè)是Full GC,也就是上面的串行畜号,很恐怖的抹估,所以內(nèi)存不是很大的,不要考慮使用它弄兜,而且它的算法十分復(fù)雜药蜻。

還有一些小的隱患是:和應(yīng)用一起征用CPU(不過(guò)這個(gè)不是大問(wèn)題,增加CPU即可)替饿、整個(gè)運(yùn)行過(guò)程中時(shí)間比并行GC長(zhǎng)(這個(gè)也不是大問(wèn)題语泽,因?yàn)槲覀兏雨P(guān)心暫停時(shí)間而不是運(yùn)行時(shí)間,因?yàn)闀和?huì)影響非常多的業(yè)務(wù))视卢。

啟動(dòng)CMS為全局GC方法(注意這個(gè)參數(shù)也不能上面的并行GC進(jìn)行混淆踱卵,Yong默認(rèn)是并行的,上面已經(jīng)說(shuō)過(guò)

-XX:+UseConcMarkSweepGC

在并發(fā)GC下啟動(dòng)增量模式,只能在CMS GC下這個(gè)參數(shù)才有效惋砂。

-XX:+CMSIncrementalMode

啟動(dòng)自動(dòng)調(diào)節(jié)duty cycle妒挎,即在CMS GC中發(fā)生的時(shí)間比率設(shè)置,也就是說(shuō)這段時(shí)間內(nèi)最大允許發(fā)生多長(zhǎng)時(shí)間的GC工作是可以調(diào)整的西饵。

-XX:+CMSIncrementalPacing

在上面這個(gè)參數(shù)設(shè)定后可以分別設(shè)置以下兩個(gè)參數(shù)(參數(shù)設(shè)置的比率酝掩,范圍為0-100):

-XX:CMSIncrementalDutyCycleMin=0
-XX:CMSIncrementalDutyCycle=10

增量GC上還有一個(gè)保護(hù)因子(CMSIncrementalSafetyFactor),不太常用;CMSIncrementalOffset提供增量GC連續(xù)時(shí)間比率的設(shè)置;CMSExpAvgFactor為增量并發(fā)的GC增加權(quán)重計(jì)算慌植。

-XX:CMSIncrementalSafetyFactor=
-XX:CMSIncrementalOffset=
-XX:CMSExpAvgFactor=

是否啟動(dòng)并行CMS GC(默認(rèn)也是開(kāi)啟的)

-XX:+CMSParallelRemarkEnabled

要單獨(dú)對(duì)CMS GC設(shè)置并行線程數(shù)就設(shè)置(默認(rèn)也不需要設(shè)置):

-XX:ParallelCMSThreads

對(duì)PernGen進(jìn)行垃圾回收:

JDK 1.5在CMS GC基礎(chǔ)上需要設(shè)置參數(shù)(也就是前提是CMS GC才有):

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

1.6以后的版本無(wú)需設(shè)置:-XX:+CMSPermGenSweepingEnabled,注意镶苞,其實(shí)一直以來(lái)Full GC都會(huì)觸發(fā)對(duì)Perm的回收過(guò)程,CMS GC需要有一些特殊照顧鞠评,雖然VM會(huì)對(duì)這塊區(qū)域回收茂蚓,但是Perm回收的條件幾乎不太可能實(shí)現(xiàn),首先需要這個(gè)類的classloader必須死掉剃幌,才可以將該classloader下所有的class干掉聋涨,也就是要么全部死掉,要么全部活著锥忿;另外牛郑,這個(gè)classloader下的class沒(méi)有任何object在使用,這個(gè)也太苛刻了吧敬鬓,因?yàn)槌R?guī)的對(duì)象申請(qǐng)都是通過(guò)系統(tǒng)默認(rèn)的淹朋,應(yīng)用服務(wù)器也有自己默認(rèn)的classloader,要讓它死掉可能性不大钉答,如果這都死掉了础芍,系統(tǒng)也應(yīng)該快掛了。

CMS GC因?yàn)槭窃诔绦蜻\(yùn)行時(shí)進(jìn)行GC数尿,不會(huì)暫停仑性,所以不能等到不夠用的時(shí)候才去開(kāi)啟GC,官方說(shuō)法是他們的默認(rèn)值是68%右蹦,但是可惜的是文檔寫(xiě)錯(cuò)了诊杆,經(jīng)過(guò)很多測(cè)試和源碼驗(yàn)證這個(gè)參數(shù)應(yīng)該是在92%的時(shí)候被啟動(dòng),雖然還有8%的空間何陆,但是還是很可憐了晨汹,當(dāng)CMS發(fā)現(xiàn)內(nèi)存實(shí)在不夠的時(shí)候又回到常規(guī)的并行GC,所以很多人在沒(méi)有設(shè)置這個(gè)參數(shù)的時(shí)候發(fā)現(xiàn)CMS GC并沒(méi)有神馬優(yōu)勢(shì)嘛贷盲,和并行GC一個(gè)鳥(niǎo)樣子甚至于更加慢淘这,所以這個(gè)時(shí)候需要設(shè)置參數(shù)(這個(gè)參數(shù)在上面已經(jīng)說(shuō)過(guò),啟動(dòng)CMS一定要設(shè)置這個(gè)參數(shù)):

-XX:CMSInitiatingOccupancyFraction=70

這樣保證Old的內(nèi)存在使用到70%的時(shí)候,就開(kāi)始啟動(dòng)CMS了铝穷;如果你真的想看看默認(rèn)值钠怯,那么就使用參數(shù):-XX:+PrintCMSInitiationStatistics 這個(gè)變量只有JDK 1.6可以使用 1.5不可以,查看實(shí)際值-XX:+PrintCMSStatistics曙聂;另外晦炊,還可以設(shè)置參數(shù)-XX:CMSInitiatingPermOccupancyFraction來(lái)設(shè)置Perm空間達(dá)到多少時(shí)啟動(dòng)CMS GC,不過(guò)意義不大筹陵。

JDK 1.6以后有些時(shí)候啟動(dòng)CMS GC是根據(jù)計(jì)算代價(jià)進(jìn)行啟動(dòng)刽锤,也就是不一定按照你指定的參數(shù)來(lái)設(shè)置的镊尺,如果你不想讓它按照所謂的成本來(lái)計(jì)算GC的話朦佩,那么你就使用一個(gè)參數(shù):-XX:+UseCMSInitiatingOccupancyOnly,默認(rèn)是false庐氮,它就只會(huì)按照你設(shè)置的比率來(lái)啟動(dòng)CMS GC了语稠。如果你的程序中有System.gc以及設(shè)置了ExplicitGCInvokesConcurrent在jdk 1.6中,這種情況使用NIO是有可能產(chǎn)生問(wèn)題的弄砍。

啟動(dòng)CMS GC的compation操作仙畦,也就是發(fā)生多少次后做一次全局的compaction:

-XX:+UseCMSCompactAtFullCollection

-XX:CMSFullGCsBeforeCompaction:發(fā)生多少次CMS Full GC,這個(gè)參數(shù)最好不要設(shè)置音婶,因?yàn)橐鯿ompaction的話慨畸,也就是真正的Full GC是串行的,非常慢衣式,讓它自己去決定什么時(shí)候需要做compaction寸士。

-XX:CMSMaxAbortablePrecleanTime=5000 設(shè)置preclean步驟的超時(shí)時(shí)間,單位為毫秒碴卧,preclean為cms gc其中一個(gè)步驟弱卡,關(guān)于cms gc步驟比較多,本文就不細(xì)節(jié)探討了住册。

并行GC在mark階段婶博,可能會(huì)同時(shí)發(fā)生minor GC,old區(qū)域也可能發(fā)生改變荧飞,于是并發(fā)GC會(huì)對(duì)發(fā)生了改變的內(nèi)容進(jìn)行remark操作凡人,這個(gè)觸發(fā)的條件是:

-XX:CMSScheduleRemarkEdenSizeThreshold

-XX:CMSScheduleRemarkEdenPenetration

即Eden區(qū)域多大的時(shí)候開(kāi)始觸發(fā),和eden使用量超過(guò)百分比多少的時(shí)候觸發(fā)叹阔,前者默認(rèn)是2M挠轴,后者默認(rèn)是50%。

但是如果長(zhǎng)期不做remark導(dǎo)致old做不了条获,可以設(shè)置超時(shí)忠荞,這個(gè)超時(shí)默認(rèn)是5秒,可以通過(guò)參數(shù):

-XX:CMSMaxAbortablePrecleanTime

-XX:+ExplicitGCInvokesConcurrent 在顯示發(fā)生GC的時(shí)候,允許進(jìn)行并行GC委煤。

-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 幾乎和上面一樣堂油,只不過(guò)多一個(gè)對(duì)Perm區(qū)域的回收而已。

補(bǔ)充:

其實(shí)JVM還有很多的版本碧绞,很多的廠商府框,與其優(yōu)化的原則,隨便舉兩個(gè)例子hotspot在GC中做的一些優(yōu)化(這里不說(shuō)代碼的編譯時(shí)優(yōu)化或運(yùn)行時(shí)優(yōu)化):

Eden申請(qǐng)的空間對(duì)象由Old區(qū)域的某個(gè)對(duì)象的一個(gè)屬性指向(也就是Old區(qū)域的這個(gè)空間不回收讥邻,Eden這塊就沒(méi)有必要考慮回收)迫靖,所以Hotspot在CPU寫(xiě)上面,做了一個(gè)屏障兴使,當(dāng)發(fā)生賦值語(yǔ)句的時(shí)候(對(duì)內(nèi)存來(lái)講賦值就是一種寫(xiě)操作)系宜,如果發(fā)現(xiàn)是一個(gè)新的對(duì)象由Old指向Eden,那么就會(huì)將這個(gè)對(duì)象記錄在一個(gè)卡片機(jī)里面发魄,這個(gè)卡片機(jī)是有很多512字節(jié)的卡片組成盹牧,當(dāng)在YGC過(guò)程中,就基本不會(huì)去移動(dòng)或者管理這塊對(duì)象(付:這種卡片機(jī)會(huì)在CMS GC的算法中使用励幼,不過(guò)和這個(gè)卡片不是放在同一個(gè)地方的汰寓,也是CMS GC的關(guān)鍵,對(duì)于CMS GC的算法細(xì)節(jié)描述苹粟,后續(xù)文章我們單獨(dú)說(shuō)明)有滑。

Old區(qū)域?qū)τ谝恍┍容^大的對(duì)象,JVM就不會(huì)去管理個(gè)對(duì)象嵌削,也就是compact過(guò)程中不會(huì)去移動(dòng)這塊對(duì)象的區(qū)域等等吧毛好。

以上大部分參數(shù)為hotspot的自帶關(guān)于性能的參數(shù),參考版本為JDK 1.5和1.6的版本掷贾,很多為個(gè)人經(jīng)驗(yàn)說(shuō)明睛榄,不足以說(shuō)明所有問(wèn)題,如果有問(wèn)題想帅,歡迎探討场靴;另外,JDK的參數(shù)是不是就只有這些呢港准,肯定并不是旨剥,我知道的也不止這些,但是有些覺(jué)得沒(méi)必要說(shuō)出來(lái)的參數(shù)和一些數(shù)學(xué)運(yùn)算的參數(shù)我就不想給出來(lái)了浅缸,比如像禁用掉GC的參數(shù)有神馬意義轨帜,我們的服務(wù)器要是把這個(gè)禁用掉干個(gè)屁啊,呵呵衩椒,做測(cè)試還可以用這玩玩蚌父,讓它不做GC直接溢出哮兰;還有一些什么計(jì)算因子啥的,還有很多復(fù)雜的數(shù)學(xué)運(yùn)算規(guī)則苟弛,要是把這個(gè)配置明白了喝滞,就太那個(gè)了,而且一般情況下也沒(méi)那個(gè)必要膏秫,JDK到現(xiàn)在的配置參數(shù)多達(dá)上500個(gè)以上右遭,要知道完的話慢慢看吧,不過(guò)意義不大缤削,而且要知道默認(rèn)值最靠譜的是看源碼而不是看文檔窘哈,官方文檔也只能保證絕大部是正確的,不能保證所有的是正確的亭敢。

本文最后追加在jdk 1.6u 24后通過(guò)上面說(shuō)明的-XX:+PrintFlagsFinal輸出的參數(shù)以及默認(rèn)值(還是那句話滚婉,在不同的平臺(tái)上是不一樣的),輸出的參數(shù)如下吨拗,可以看看JVM的參數(shù)是相當(dāng)?shù)亩嗦模瑓?shù)如此之多婿斥,你只需要掌握關(guān)鍵即可劝篷,參數(shù)還有很多有沖突的,不要糾結(jié)于每一個(gè)參數(shù)的細(xì)節(jié):

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末民宿,一起剝皮案震驚了整個(gè)濱河市娇妓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌活鹰,老刑警劉巖哈恰,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異志群,居然都是意外死亡着绷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門锌云,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)荠医,“玉大人,你說(shuō)我怎么就攤上這事桑涎”蛳颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵攻冷,是天一觀的道長(zhǎng)娃胆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)等曼,這世上最難降的妖魔是什么里烦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任凿蒜,我火速辦了婚禮,結(jié)果婚禮上胁黑,老公的妹妹穿的比我還像新娘篙程。我一直安慰自己,他們只是感情好别厘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布虱饿。 她就那樣靜靜地躺著,像睡著了一般触趴。 火紅的嫁衣襯著肌膚如雪氮发。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天冗懦,我揣著相機(jī)與錄音爽冕,去河邊找鬼。 笑死披蕉,一個(gè)胖子當(dāng)著我的面吹牛颈畸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播没讲,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼眯娱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了爬凑?” 一聲冷哼從身側(cè)響起徙缴,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘁信,沒(méi)想到半個(gè)月后于样,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡潘靖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年穿剖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卦溢。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡糊余,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出既绕,到底是詐尸還是另有隱情啄刹,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布凄贩,位于F島的核電站誓军,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疲扎。R本人自食惡果不足惜昵时,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一捷雕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧壹甥,春花似錦救巷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至溯职,卻和暖如春精盅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谜酒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工叹俏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僻族。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓粘驰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親述么。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝌数,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 原文閱讀 前言 這段時(shí)間懈怠了,罪過(guò)碉输! 最近看到有同事也開(kāi)始用上了微信公眾號(hào)寫(xiě)博客了籽前,挺好的~給他們點(diǎn)贊,這博客我...
    碼農(nóng)戲碼閱讀 5,962評(píng)論 2 31
  • Java 虛擬機(jī)有自己完善的硬件架構(gòu), 如處理器敷钾、堆棧、寄存器等肄梨,還具有相應(yīng)的指令系統(tǒng)阻荒。JVM 屏蔽了與具體操作系...
    尹小凱閱讀 1,689評(píng)論 0 10
  • 1 CPU和內(nèi)存的交互 了解jvm內(nèi)存模型前,了解下cpu和計(jì)算機(jī)內(nèi)存的交互情況众羡∏壬模【因?yàn)镴ava虛擬機(jī)內(nèi)存模型定義...
    Garwer閱讀 366,828評(píng)論 54 549
  • 轉(zhuǎn)載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,366評(píng)論 1 56
  • 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別 內(nèi)存溢出:out of memory,是指程序在申請(qǐng)內(nèi)存時(shí)粱侣,沒(méi)有足夠的內(nèi)存空間供其使用羊壹,...
    Aimerwhy閱讀 741評(píng)論 0 1