1 調(diào)優(yōu)層次
性能調(diào)優(yōu)包含多個層次蒿柳,比如:架構(gòu)調(diào)優(yōu)、代碼調(diào)優(yōu)漩蟆、JVM調(diào)優(yōu)垒探、數(shù)據(jù)庫調(diào)優(yōu)、操作系統(tǒng)調(diào)優(yōu)等怠李。
架構(gòu)調(diào)優(yōu)和代碼調(diào)優(yōu)是JVM調(diào)優(yōu)的基礎(chǔ)圾叼,其中架構(gòu)調(diào)優(yōu)是對系統(tǒng)影響最大的。
2 調(diào)優(yōu)指標(biāo)
- 吞吐量:運(yùn)行用戶代碼的時(shí)間占總運(yùn)行時(shí)間的比例 (總運(yùn)行時(shí)間=程序的運(yùn)行時(shí)間+內(nèi)存回收的時(shí)間)捺癞;
- 暫停時(shí)間:執(zhí)行垃圾收集時(shí)夷蚊,程序的工作線程被暫停的時(shí)間;
- 內(nèi)存占用:java堆區(qū)所占的內(nèi)存大兴杞椤惕鼓;
這三者共同構(gòu)成一個“不可能三角”。三者總體的表現(xiàn)會隨著技術(shù)進(jìn)步而越來越好唐础。一款優(yōu)秀的收集器通常最多同時(shí)滿足其中的兩項(xiàng)箱歧。
簡單來說,主要抓住兩點(diǎn):
- 吞吐量
吞吐量優(yōu)先一膨,意味著在單位時(shí)間內(nèi)呀邢,STW的時(shí)間最短 - 暫停時(shí)間
暫停時(shí)間優(yōu)先,意味這盡可能讓單次STW的時(shí)間最短
在設(shè)計(jì)(或使用)GC算法時(shí)豹绪,必須確定我們的目標(biāo):一個GC算法只可能針對兩個目標(biāo)之一(即只專注于較大吞吐量或最小暫停時(shí)間)驼鹅,或嘗試找一個二者的折衷。
現(xiàn)在標(biāo)準(zhǔn)森篷,在最大吞吐量優(yōu)先的情況下输钩,降低停頓時(shí)間。
3 JVM調(diào)優(yōu)原則
3.1 優(yōu)先原則
優(yōu)先架構(gòu)調(diào)優(yōu)和代碼調(diào)優(yōu)仲智,JVM優(yōu)化是不得已的手段买乃,大多數(shù)的Java應(yīng)用不需要進(jìn)行JVM優(yōu)化
3.2 堆設(shè)置
參數(shù)-Xms和-Xmx,通常設(shè)置為相同的值钓辆,避免運(yùn)行時(shí)要不斷擴(kuò)展JVM內(nèi)存剪验,建議擴(kuò)大至3-4倍FullGC后的老年代空間占用。
3.3 年輕代設(shè)置
參數(shù)-Xmn前联,1-1.5倍FullGC之后的老年代空間占用功戚。
避免新生代設(shè)置過小,當(dāng)新生代設(shè)置過小時(shí)似嗤,會帶來兩個問題:一是minor GC次數(shù)頻繁啸臀,二是可能導(dǎo)致 minor GC對象直接進(jìn)老年代。當(dāng)老年代內(nèi)存不足時(shí)烁落,會觸發(fā)Full GC乘粒。
避免新生代設(shè)置過大豌注,當(dāng)新生代設(shè)置過大時(shí),會帶來兩個問題:一是老年代變小灯萍,可能導(dǎo)致Full GC頻繁執(zhí)行轧铁;二是 minor GC 執(zhí)行回收的時(shí)間大幅度增加。
3.4 老年代設(shè)置
-
注重低延遲的應(yīng)用
- 老年代使用并發(fā)收集器旦棉,所以其大小需要小心設(shè)置齿风,一般要考慮并發(fā)會話率和會話持續(xù)時(shí)間等一些參數(shù)
- 如果堆設(shè)置偏小,可能會造成內(nèi)存碎片绑洛、高回收頻率以及應(yīng)用暫停
- 如果堆設(shè)置偏大救斑,則需要較長的收集時(shí)間
吞吐量優(yōu)先的應(yīng)用
一般吞吐量優(yōu)先的應(yīng)用都有一個較大的年輕代和一個較小的老年代。原因是诊笤,這樣可以盡可能回收掉大部分短期對象系谐,減少中期的對象巾陕,而老年代盡可能存放長期存活對象
3.5 方法區(qū)設(shè)置
基于jdk1.7版本讨跟,永久代:參數(shù)-XX:PermSize和-XX:MaxPermSize;
基于jdk1.8版本鄙煤,元空間:參數(shù) -XX:MetaspaceSize和-XX:MaxMetaspaceSize晾匠;
通常設(shè)置為相同的值,避免運(yùn)行時(shí)要不斷擴(kuò)展梯刚,建議擴(kuò)大至1.2-1.5倍FullGc后的永久帶空間占用凉馆。
3.6 GC設(shè)置
3.6.1 GC發(fā)展階段
Serial?Parallel(并行) ?CMS(并發(fā))? G1?ZGC
截至jdk1.8 ,一共有7款不同垃圾收集器亡资。每一款不同的垃圾收集器都有不同的特點(diǎn)澜共,在具體使用的時(shí)候,需要根據(jù)具體的情況選擇不同的垃圾回收器
垃圾收集器 | 分類 | 作用位置 | 使用算法 | 特點(diǎn) | 使用場景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 復(fù)制算法 | 響應(yīng)速度優(yōu)先 | 單CPU環(huán)境下client模式 |
ParNew | 并行 | 新生代 | 復(fù)制算法 | 響應(yīng)速度優(yōu)先 | 多CPU環(huán)境下Server模式下與CMS配合使用 |
Parallel | 并行 | 新生代 | 復(fù)制算法 | 吞吐量優(yōu)先 | 適用于后臺運(yùn)算而不需要太多交互的場景 |
Serial Old | 串行 | 老年代 | 標(biāo)記-整理 | 響應(yīng)速度優(yōu)先 | 單CPU環(huán)境下client模式 |
Parallel Old | 并行 | 老年代 | 標(biāo)記-整理 | 吞吐量優(yōu)先 | 適用于后臺運(yùn)算而不需要太多交互的場景 |
CMS | 并發(fā) | 老年代 | 標(biāo)記-清除 | 響應(yīng)速度優(yōu)先 | 互聯(lián)網(wǎng)或B/S業(yè)務(wù) |
G1 | 并發(fā)锥腻、并行 | 新生代嗦董、老年代 | 復(fù)制算法、標(biāo)記-整理 | 響應(yīng)速度優(yōu)先 | 面向服務(wù)端應(yīng)用 |
3.6.2 G1的適用場景
- 面向服務(wù)端應(yīng)用瘦黑,針對具有大內(nèi)存京革、多處理器的機(jī)器。(在普通大小的堆里表現(xiàn)并不驚喜)
- 最主要的應(yīng)用是需要低GC延遲并具有大堆的應(yīng)用程序提供解決方案(G1通過每次只清理一部分而不是全部Region的增量式清理來保證每次GC停頓時(shí)間不會過長)
- 在堆大小約6GB或更大時(shí)幸斥,可預(yù)測的暫停時(shí)間可以低于0.5秒
- 用來替換掉JDK1.5中的CMS收集器匹摇,以下情況,使用G1可能比CMS好
- 超過50% 的java堆被活動數(shù)據(jù)占用
- 對象分配頻率或年代提升頻率變化很大
- GC停頓時(shí)間過長(大于0.5至1秒)
- 從經(jīng)驗(yàn)上來說甲葬,整體而言:
- 小內(nèi)存應(yīng)用上廊勃,CMS大概率會優(yōu)于 G1;
- 大內(nèi)存應(yīng)用上经窖,G1則很可能更勝一籌供搀。
這個臨界點(diǎn)大概是在 6~8G 之間(經(jīng)驗(yàn)值)
3.6.3 其他收集器適用場景
- 如果你想要最小化地使用內(nèi)存和并行開銷隅居,請選擇Serial Old(老年代) + Serial(年輕代)
- 如果你想要最大化應(yīng)用程序的吞吐量,請選擇Parallel Old(老年代) + Parallel(年輕代)
- 如果你想要最小化GC的中斷或停頓時(shí)間葛虐,請選擇CMS(老年代) + ParNew(年輕代)
4 JVM調(diào)優(yōu)步驟
4.1 監(jiān)控分析
分析GC日志及dump文件胎源,判斷是否需要優(yōu)化,確定瓶頸問題點(diǎn)屿脐。
4.1.1 如何生成GC日志
常用參數(shù)部分會詳細(xì)講解如何生成GC日志
4.1.2 如何產(chǎn)生dump文件
4.1.2.1 JVM的配置文件中配置
JVM啟動時(shí)增加兩個參數(shù):
# 出現(xiàn)OOME時(shí)生成堆dump:
-XX:+HeapDumpOnOutOfMemoryError
# 生成堆文件地址:
-XX:HeapDumpPath=/home/hadoop/dump/
4.1.2.2 jmap生成
發(fā)現(xiàn)程序異常前通過執(zhí)行指令涕蚤,直接生成當(dāng)前JVM的dump文件
jmap -dump:file=文件名.dump [pid]
# 9257是指JVM的進(jìn)程號
jmap -dump:format=b,file=testmap.dump 9257
第一種方式是一種事后方式,需要等待當(dāng)前JVM出現(xiàn)問題后才能生成dump文件的诵,實(shí)時(shí)性不高万栅;
第二種方式在執(zhí)行時(shí),JVM是暫停服務(wù)的西疤,所以對線上的運(yùn)行會產(chǎn)生影響烦粒。
所以建議第一種方式。
4.1.2.3 第三方可視化工具生成
4.2 判斷
如果各項(xiàng)參數(shù)設(shè)置合理代赁,系統(tǒng)沒有超時(shí)日志或異常信息出現(xiàn)扰她,GC頻率不高,GC耗時(shí)不高芭碍,那么沒有必要進(jìn)行GC優(yōu)化徒役,如果GC時(shí)間超過1-3秒,或者頻繁GC窖壕,則必須優(yōu)化忧勿。
遇到以下情況,就需要考慮進(jìn)行JVM調(diào)優(yōu):
- 系統(tǒng)吞吐量與響應(yīng)性能不高或下降瞻讽;
- Heap內(nèi)存(老年代)持續(xù)上漲達(dá)到設(shè)置的最大內(nèi)存值鸳吸;
- Full GC 次數(shù)頻繁;
- GC 停頓時(shí)間過長(超過1秒)速勇;
- 應(yīng)用出現(xiàn)OutOfMemory等內(nèi)存異常晌砾;
- 應(yīng)用中有使用本地緩存且占用大量內(nèi)存空間;
4.3 確定目標(biāo)
調(diào)優(yōu)的最終目的都是為了應(yīng)用程序使用最小的硬件消耗來承載更大的吞吐量或者低延遲快集。
jvm調(diào)優(yōu)主要是針對垃圾收集器的收集性能優(yōu)化贡羔,減少GC的頻率和Full GC的次數(shù),令運(yùn)行在虛擬機(jī)上的應(yīng)用能夠使用更少的內(nèi)存个初、高吞吐量乖寒、低延遲。
下面列舉一些JVM調(diào)優(yōu)的量化目標(biāo)參考實(shí)例院溺,注意:不同應(yīng)用的JVM調(diào)優(yōu)量化目標(biāo)是不一樣的楣嘁。
- 堆內(nèi)存使用率<=70%;
- 老年代內(nèi)存使用率<=70%;
- avgpause<=1秒;
- Full GC次數(shù)0或avg pause interval>=24小時(shí) ;
4.4 調(diào)整參數(shù)
調(diào)優(yōu)一般是從滿足程序的內(nèi)存使用需求開始的,之后是時(shí)間延遲的要求,最后才是吞吐量的要求逐虚。
要基于這個步驟來不斷優(yōu)化聋溜,每一個步驟都是進(jìn)行下一步的基礎(chǔ),不可逆行之叭爱。
4.5 對比調(diào)優(yōu)前后指標(biāo)差異
4.6 重復(fù)以上過程
4.7 應(yīng)用
找到合適的參數(shù)缴渊,先在單臺服務(wù)器上試運(yùn)行永部,然后將這些參數(shù)應(yīng)用到所有服務(wù)器,并進(jìn)行后續(xù)跟蹤。
5 JVM調(diào)優(yōu)工具
5.1 jps
jps:JVM Process Status Tool
jps可以查看Java進(jìn)程稍坯,相當(dāng)于Linux下的ps命令窟哺,只不過它只列出Java進(jìn)程枷餐。
5.1.1 使用語法
jps:列出Java程序進(jìn)程ID和Main函數(shù)名稱
jps -q:只輸出進(jìn)程ID
jps -m:輸出傳遞給Java進(jìn)程(主函數(shù))的參數(shù)
jps -l:輸出主函數(shù)的完整路徑
jps -v:顯示傳遞給Java虛擬的參數(shù)
5.1.2 示例
5.2 jstat
jstat:JVM Statistics Monitoring Tool
jstat可以查看Java程序運(yùn)行時(shí)相關(guān)信息残黑,可以通過它查看堆信息的相關(guān)情況
5.2.1 使用語法
jstat -<options> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
5.2.2 options可選值
-class:顯示ClassLoader的相關(guān)信息
-compiler:顯示JIT編譯的相關(guān)信息
-gc:顯示與GC相關(guān)信息
-gccapacity:顯示各個代的容量和使用情況
-gccause:顯示垃圾收集相關(guān)信息(同-gcutil),同時(shí)顯示最后一次或當(dāng)前正在發(fā)生的垃圾收集的誘發(fā)原因
-gcnew:顯示新生代信息
-gcnewcapacity:顯示新生代大小和使用情況
-gcold:顯示老年代信息
-gcoldcapacity:顯示老年代大小
-gcpermcapacity:顯示永久代大小
-gcutil:顯示垃圾收集信息
-printcompilation:輸出JIT編譯的方法信息
-t:在輸出信息前加上一個Timestamp列晃危,顯示程序的運(yùn)行時(shí)間
-h:可以在周期性數(shù)據(jù)輸出后叙赚,輸出多少行數(shù)據(jù)后,跟著一個表頭信息
interval:用于指定輸出統(tǒng)計(jì)數(shù)據(jù)的周期僚饭,單位為毫秒
count:用于指定一個輸出多少次數(shù)據(jù)
5.2.3 示例
示例一
顯示GC相關(guān)信息
jstat -gc 7063 500 4
7063 是進(jìn)程ID 震叮,采樣時(shí)間間隔為500ms,采樣數(shù)為4
S0C:年輕代中第一個survivor(幸存區(qū))的容量 (字節(jié))
S1C:年輕代中第二個survivor(幸存區(qū))的容量 (字節(jié))
S0U:年輕代中第一個survivor(幸存區(qū))目前已使用空間 (字節(jié))
S1U:年輕代中第二個survivor(幸存區(qū))目前已使用空間 (字節(jié))
EC :年輕代中Eden(伊甸園)的容量 (字節(jié))
EU :年輕代中Eden(伊甸園)?前已使?空間 (字節(jié))
OC :Old代的容量 (字節(jié))
OU :Old代目前已使用空間 (字節(jié))
MC:metaspace(元空間)的容量 (字節(jié))
MU:metaspace(元空間)目前已使用空間 (字節(jié))
CCSC:壓縮類空間大小
CCSU:壓縮類空間使用大小
YGC :從應(yīng)用程序啟動到采樣時(shí)年輕代中g(shù)c次數(shù)
YGCT :從應(yīng)用程序啟動到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)
FGC :從應(yīng)用程序啟動到采樣時(shí)old代(全gc)gc次數(shù)
FGCT :從應(yīng)用程序啟動到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動到采樣時(shí)gc用的總時(shí)間(s)
示例二
顯示垃圾收集相關(guān)信息
jstat -gcutil 7737 5s 5
S0 年輕代中第一個survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
S1 年輕代中第二個survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
E 年輕代中Eden(伊甸園)已使用的占當(dāng)前容量百分比
O old代已使用的占當(dāng)前容量百分比
M metaspace已使用的占當(dāng)前容量百分比
CCS 壓縮使用比例
YGC 從應(yīng)用程序啟動到采樣時(shí)年輕代中g(shù)c次數(shù)
YGCT 從應(yīng)用程序啟動到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)
FGC 從應(yīng)用程序啟動到采樣時(shí)old代(全gc)gc次數(shù)
FGCT 從應(yīng)用程序啟動到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT 從應(yīng)用程序啟動到采樣時(shí)gc用的總時(shí)間(s)
5.3 jinfo
jinfo:Java Configuration Info
jinfo可以用來查看正在運(yùn)行的java程序的擴(kuò)展參數(shù)浪慌,甚至支持運(yùn)行時(shí)修改部分參數(shù)
5.3.1 使用語法
jinfo [option] <pid>
5.3.2 option可選值
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both of the above
-h | -help to print this help message
5.3.2 示例
示例一
查看堆的最大值
~ jinfo -flag MaxHeapSize 8384
-XX:MaxHeapSize=10485760
示例二
查看所有參數(shù)
~ jinfo -flags 8384
Attaching to process ID 8384, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=10485760 -
XX:MaxHeapSize=10485760 -XX:MaxNewSize=3145728 -XX:MinHeapDeltaBytes=524288 -
XX:NewSize=3145728 -XX:OldSize=7340032 -XX:+UseCompressedClassPointers -
XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
Command line: -Xms10m -Xmx10m -Dfile.encoding=UTF-8
示例三
查看使用的垃圾回收器
~ jinfo -flag UseParallelGC 8384
-XX:+UseParallelGC
~ jinfo -flag UseConcMarkSweepGC 8384
-XX:-UseConcMarkSweepGC
示例四
設(shè)置日志打印
~ jinfo -flag PrintGCDetails 8384
-XX:-PrintGCDetails
~ jinfo -flag +PrintGCDetails 8384
~ jinfo -flag PrintGCDetails 8384
-XX:+PrintGCDetails
~ jinfo -flag -PrintGCDetails 8384
~ jinfo -flag PrintGCDetails 8384
-XX:-PrintGCDetails
5.4 jmap
jmap:Memory Map
jmap可以查看堆內(nèi)存使用狀況冤荆,一般結(jié)合jhat使用朴则。
5.4.1 使用語法
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
option:選項(xiàng)參數(shù)权纤。
pid:需要打印配置信息的進(jìn)程ID。
executable:產(chǎn)生核心dump的Java可執(zhí)行文件乌妒。
core:需要打印配置信息的核心文件汹想。
server-id:可選的唯一id,如果相同的遠(yuǎn)程主機(jī)上運(yùn)行了多臺調(diào)試服務(wù)器撤蚊,用此選項(xiàng)參數(shù)標(biāo)識服務(wù)器古掏。
remote server IP or hostname:遠(yuǎn)程調(diào)試服務(wù)器的IP地址或主機(jī)名。
5.4.2 option可選值
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
-F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
no option: 查看進(jìn)程的內(nèi)存映像信息,類似 Solaris pmap 命令侦啸。
heap: 顯示Java堆詳細(xì)信息
histo[:live]: 顯示堆中對象的統(tǒng)計(jì)信息
clstats:打印類加載器信息
finalizerinfo: 顯示在F-Queue隊(duì)列等待Finalizer線程執(zhí)行finalizer方法的對象
dump:<dump-options>:生成堆轉(zhuǎn)儲快照
F:當(dāng)-dump沒有響應(yīng)時(shí)槽唾,使用-dump或者-histo參數(shù)。在這個模式下光涂,live子參數(shù)無效
help:打印幫助信息
J<flag>:指定傳遞給運(yùn)行jmap的JVM的參數(shù)
dump-options可選值
-live dump only live objects; if not specified,all objects in the heap are dumped.
-format=b binary format
-file=<file> dump heap to <file>
Example:jmap -dump:live,format=b,file=heap.bin <pid>
5.4.3 示例
示例一
顯示Java堆詳細(xì)信息
jmap -heap pid
打印一個堆的摘要信息庞萍,包括使用的GC算法、堆配置信息和各內(nèi)存區(qū)域內(nèi)存使用信息
~ jmap -heap 8985
Attaching to process ID 8985, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 524288000 (500.0MB)
NewSize = 174587904 (166.5MB)
MaxNewSize = 174587904 (166.5MB)
OldSize = 349700096 (333.5MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 131596288 (125.5MB)
used = 127090976 (121.20339965820312MB)
free = 4505312 (4.296600341796875MB)
96.57641407028137% used
From Space:
capacity = 21495808 (20.5MB)
used = 21477712 (20.482742309570312MB)
free = 18096 (0.0172576904296875MB)
99.91581614424543% used
To Space:
capacity = 21495808 (20.5MB)
used = 0 (0.0MB)
free = 21495808 (20.5MB)
0.0% used
PS Old Generation
capacity = 349700096 (333.5MB)
used = 100703528 (96.03836822509766MB)
free = 248996568 (237.46163177490234MB)
28.79711191157351% used
2156 interned Strings occupying 152440 bytes.
示例二
顯示堆中對象的統(tǒng)計(jì)信息
jmap -histo:live pid
其中包括每個Java類忘闻、對象數(shù)量钝计、內(nèi)存大小(單位:字節(jié))、完全限定的類名。打印的虛擬機(jī)內(nèi)部的類名稱將會帶有一個’*’前綴私恬。如果指定了live子選項(xiàng)债沮,則只計(jì)算活動的對象。
~ jmap -histo:live 8985
num #instances #bytes class name
----------------------------------------------
1: 3682 339156840 [B
2: 3806 408160 [C
3: 3794 91056 java.lang.String
4: 593 67480 java.lang.Class
5: 587 54568 [Ljava.lang.Object;
6: 3273 52368 com.kkb.example.HeapInstanceTest
示例三
打印類加載器信息
jmap -clstats pid
-clstats是-permstat的替代方案本鸣,在JDK8之前疫衩,-permstat用來打印類加載器的數(shù)據(jù)打印Java堆內(nèi)存的永久保存區(qū)域的類加載器的智能統(tǒng)計(jì)信息。對于每個類加載器而言荣德,它的名稱隧土、活躍 度、地址命爬、父類加載器曹傀、它所加載的類的數(shù)量和大小都會被打印。此外饲宛,包含的字符串?dāng)?shù)量和大小也會被打印皆愉。
~ jmap -clstats 8985
Attaching to process ID 8985, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing
liveness......................................................................
.............................done.
class_loader classes bytes parent_loader alive? type
<bootstrap> 517 969116 null live <internal>
0x00000007af095a08 0 0 0x00000007ae86f288 live
java/util/ResourceBundle$RBClassLoader@0x00000007c00555e8
0x00000007ae86f288 9 29861 0x00000007ae8770f8 live
sun/misc/Launcher$AppClassLoader@0x00000007c000f6a0
0x00000007ae8770f8 0 0 null live
sun/misc/Launcher$ExtClassLoader@0x00000007c000fa48
total = 4 526 998977 N/A alive=4, dead=0 N/A
示例四
打印正等候回收的對象的信息
jmap -finalizerinfo pid
~ jmap -finalizerinfo 10067
Attaching to process ID 10067, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Number of objects pending for finalization: 0
Number of objects pending for finalization: 0 說明當(dāng)前F-QUEUE隊(duì)列中并沒有等待Fializer線程執(zhí)行final
示例五
生成堆轉(zhuǎn)儲快照dump文件
jmap -dump:format=b,file=heapdump.dump pid
以hprof二進(jìn)制格式轉(zhuǎn)儲Java堆到指定filename的文件中。live子選項(xiàng)是可選的艇抠。如果指定了live 子選項(xiàng)幕庐,堆中只有活動的對象會被轉(zhuǎn)儲。想要瀏覽heap dump家淤,你可以使用jhat(Java堆分析?具)讀取生成的文件异剥。
這個命令執(zhí)行,JVM會將整個heap的信息dump寫入到?個文件絮重,heap如果比較大的話冤寿,就會導(dǎo)致這個過程比較耗時(shí),并且執(zhí)行的過程中為了保證dump的信息是可靠的青伤,所以會暫停應(yīng)用督怜, 線上系統(tǒng)慎用。
~ jmap -dump:format=b,file=heapdump.dump 10067
Dumping heap to /Users/hadoop/heapdump.dump ...
5.5 jhat
jhat:Java Heap Analysis Tool
jhat 命令解析Java堆轉(zhuǎn)儲文件并啟動一個 web server狠角,然后用瀏覽器來查看号杠、瀏覽 dump 出來的 heap。
jhat 命令支持預(yù)先設(shè)計(jì)的查詢丰歌,比如顯示某個類的所有實(shí)例姨蟋。 還支持對象查詢語言(OQL, Object Query Language)。 OQL有點(diǎn)類似SQL立帖,專門用來查詢堆轉(zhuǎn)儲眼溶。
5.5.1 使用語法
jhat [ options ] heap-dump-file
5.5.2 options可選值
-stack false|true
關(guān)閉對象分配調(diào)用棧跟蹤(tracking object allocation call stack)。 如果分配位置信息在堆轉(zhuǎn)儲中不可用厘惦,則必須將此標(biāo)志設(shè)置為 false偷仿。 默認(rèn)值為 true 哩簿。
-refs false|true
關(guān)閉對象引用跟蹤(tracking of references to objects)。 默認(rèn)值為 true 酝静。 默認(rèn)情況下, 返回的指針是指向其他特定對象的對象节榜,如反向鏈接或輸入引用(referrers or incoming references), 會統(tǒng)計(jì)、計(jì)算堆中的所有對象别智。
-port port-number
設(shè)置 jhat HTTP server 的端口號宗苍。 默認(rèn)值 7000 。
-exclude exclude-file
指定對象查詢時(shí)需要排除的數(shù)據(jù)成員列表文件(a file that lists data members that should be excluded from the reachable objects query)薄榛。 例如, 如果文件列列出了 java.lang.String.value , 那么當(dāng)從某個特定對象 Object o 計(jì)算可達(dá)的對象列表時(shí), 引用路徑涉及 java.lang.String.value 的都會被排除讳窟。
-baseline exclude-file
指定一個基準(zhǔn)堆轉(zhuǎn)儲(baseline heap dump)。 在兩個 heap dumps 中有相同 object ID 的對象會被標(biāo)記為不是新的(marked as not being new)敞恋,其他對象被標(biāo)記為新的(new)丽啡。 在比較兩個不同的堆轉(zhuǎn)儲時(shí)很有用。
-debug int
設(shè)置 debug 級別硬猫。 0表示不輸出調(diào)試信息补箍。 值越大則表示輸出更詳細(xì)的 debug 信息。
-version
啟動后只顯示版本信息就退出
-h
顯示幫助信息并退出啸蜜。 同 -help
-help
顯示幫助信息并退出坑雅。 同 -h
-J< flag >
因?yàn)閖hat命令實(shí)際上會啟動一個JVM來執(zhí)行, 通過 -J 可以在啟動JVM時(shí)傳入一些啟動參數(shù)。 例如, -J-Xmx512m 則指定運(yùn)行jhat的Java虛擬機(jī)使用的最大堆內(nèi)存為 512 MB衬横。 如果需要使用多個JVM啟動參數(shù)裹粤,則傳多多個 -Jxxxxxx。
5.5.3 示例
利用jhat分析剛剛jmap輸出的堆文件
這樣就啟動起來了一個簡易的HTTP服務(wù)蜂林,端口號是7000遥诉,嘗試一下用瀏覽器訪問?下它,本地的可以通過http://localhost:7000就可以得到這樣的頁面:
jhat啟動后顯示的html頁面中包含有:
- All classes including platform:顯示出堆中所包含的所有的類
- Show all members of the rootset :從根集能引用到的對象
- Show instance counts for all classes (including platform/excluding platform):顯示平臺包括的所有類的實(shí)例數(shù)量
- Show heap histogram:堆實(shí)例的分布表
- Show finalizer summary:Finalizer 摘要
- Execute Object Query Language (OQL) query:執(zhí)行對象查詢語句(OQL)
select a from [I a where a.length > 256 //查詢長度大于256的數(shù)組
5.6 jstack
jstack:Java Stack Trace
jstack是java虛擬機(jī)自帶的一種堆棧跟蹤工具悉尾。jstack用于生成java虛擬機(jī)當(dāng)前時(shí)刻的線程快照突那。線程快照是當(dāng)前java虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合挫酿,生成線程快照的主要目的是定位線程出現(xiàn)長時(shí)間停頓的原因构眯,如線程間死鎖、死循環(huán)早龟、請求外部資源導(dǎo)致的長時(shí)間等待等惫霸。 線程出現(xiàn)停頓的時(shí)候通過jstack來查看各個線程的調(diào)用堆棧,就可以知道沒有響應(yīng)的線程到底在后臺做什么事情葱弟,或者等待什么資源壹店。
如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息芝加,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問題硅卢。另外射窒,jstack工具還可以附屬到正在運(yùn)行的java程序中,看到當(dāng)時(shí)運(yùn)行的java程序的java stack和native stack的信息, 如果現(xiàn)在運(yùn)行的java程序呈現(xiàn)hung的狀態(tài)将塑,jstack是非常有用的脉顿。
5.6.1 使用語法
jstack [ option ] pid 查看當(dāng)前時(shí)間點(diǎn),指定進(jìn)程的dump堆棧信息点寥。
jstack [ option ] pid > 文件 將當(dāng)前時(shí)間點(diǎn)的指定進(jìn)程的dump堆棧信息艾疟,寫入到指定文件中。
注:若該文件不存在敢辩,則會自動生成蔽莱;若該文件存在,則會覆蓋源文件戚长。
jstack [ option ] executable core 查看當(dāng)前時(shí)間點(diǎn)盗冷,core文件的dump堆棧信息。
jstack [ option ] [server_id@]<remote server IP or hostname> 查看當(dāng)前時(shí)間點(diǎn)同廉,遠(yuǎn)程機(jī)器的dump堆棧信息正塌。
5.6.2 option可選值
-F 強(qiáng)制jstack。當(dāng)進(jìn)程掛起了恤溶,此時(shí)'jstack [-l] pid'是沒有響應(yīng)的乓诽,這時(shí)候可使用此參數(shù)來強(qiáng)制打印堆棧信息,一般情況不需要使用咒程。
-m 打印java和native c/c++框架的所有棧信息鸠天。可以打印JVM的堆棧帐姻,以及Native的棧幀稠集,一般應(yīng)用排查不需要使用。
-l 長列表饥瓷。打印關(guān)于鎖的附加信息剥纷。例如屬于java.util.concurrent的ownable synchronizers列表,會使得JVM停頓得?久得多(可能會差很多倍呢铆,?如普通的jstack可能?毫秒和?次GC沒區(qū)別晦鞋,加了-l 就是近一秒的時(shí)間),-l 建議不要用棺克。一般情況不需要使用悠垛。
-h or -hel 打印幫助信息
在thread dump中,要留意下面幾種狀態(tài)
- 死鎖娜谊,Deadlock(重點(diǎn)關(guān)注)
- 等待資源确买,Waiting on condition(重點(diǎn)關(guān)注)
- 等待獲取監(jiān)視器,Waiting on monitor entry(重點(diǎn)關(guān)注)
- 阻塞纱皆,Blocked(重點(diǎn)關(guān)注)
- 執(zhí)行中湾趾,Runnable
- 暫停芭商,Suspended
- 對象等待中,Object.wait() 或 TIMED_WAITING
- 停止搀缠,Parked
5.6.3 示例
示例一
示例二
將指定進(jìn)程的當(dāng)前堆棧情況記錄到某個?件中
示例三
統(tǒng)計(jì)線程數(shù)
示例四
檢測死鎖
5.7 hprof
hprof:Heap/CPU Profiling Tool 能夠展現(xiàn)CPU使用率蓉坎,統(tǒng)計(jì)堆內(nèi)存使用情況。
J2SE中提供了一個簡單的命令行工具來對java程序的cpu和heap進(jìn)行profiling胡嘿,叫做HPROF蛉艾。HPROF實(shí)際上是JVM中的一個native的庫,它會在JVM啟動的時(shí)候通過命令行參數(shù)來動態(tài)加載衷敌,并成為JVM進(jìn)程的一部分勿侯。若要在java進(jìn)程啟動的時(shí)候使用HPROF,用戶可以通過各種命令行參數(shù)類型來使用HPROF對java進(jìn)程的heap或者(和)cpu進(jìn)行profiling的功能缴罗。HPROF產(chǎn)生的profiling數(shù)據(jù)可以是二進(jìn)制的助琐,也可以是文本格式的。這些日志可以用來跟蹤和分析java進(jìn)程的性能問題和瓶頸面氓,解決內(nèi)存使用上不優(yōu)的地方或者程序?qū)崿F(xiàn)上的不優(yōu)之處兵钮。二進(jìn)制格式的日志還可以被JVM中的HAT工具來進(jìn)行瀏覽和分析,用以觀察java進(jìn)程的heap中各種類型和數(shù)據(jù)的情況舌界。在J2SE 5.0以后的版本中掘譬,HPROF已經(jīng)被并入到一個叫做Java Virtual Machine Tool Interface(JVM TI)中。
5.7.1 使用語法
java -agentlib:hprof[=options] ToBeProfiledClass
java -Xrunprof[:options] ToBeProfiledClass
javac -J-agentlib:hprof[=options] ToBeProfiledClass
5.7.2 options可選值
Option Name and Value Description Default
--------------------- ----------- -------
heap=dump|sites|all heap profiling all
cpu=samples|times|old CPU usage off
monitor=y|n monitor contention n
format=a|b text(txt) or binary output a
file=<file> write data to file java.hprof[.txt]
net=<host>:<port> send data over a socket off
depth=<size> stack trace depth 4
interval=<ms> sample interval in ms 10
cutoff=<value> output cutoff point 0.0001
lineno=y|n line number in traces? y
thread=y|n thread in traces? n
doe=y|n dump on exit? y
msa=y|n Solaris micro state accounting n
force=y|n force output to <file> y
verbose=y|n print messages about dumps y
5.7.3 示例
官方示例
CPU Usage Sampling Profiling(cpu=samples)的例子
下面每隔20毫秒采樣CPU消耗信息呻拌,堆棧深度為3葱轩,生成的profile文件名稱是java.hprof.txt,在當(dāng)前目錄藐握。
java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello
CPU Usage Times Profiling(cpu=times)的例子
它相對于CPU Usage Sampling Profile能夠獲得更加細(xì)粒度的CPU消耗信息靴拱,能夠細(xì)到每個?法調(diào)?的開始和結(jié)束,它的實(shí)現(xiàn)使用了字節(jié)碼注入技術(shù)(BCI)
javac -J-agentlib:hprof=cpu=times Hello.java
Heap Allocation Profiling(heap=sites)的例子
javac -J-agentlib:hprof=heap=sites Hello.java
Heap Dump(heap=dump)的例子
它能比上面的Heap Allocation Profiling生成更詳細(xì)的Heap Dump信息:
javac -J-agentlib:hprof=heap=dump Hello.java
雖然在JVM啟動參數(shù)中加入-Xrunprof:heap=sites參數(shù)可以生成CPU/Heap Profile文件猾普,但對JVM性
能影響非常大袜炕,不建議在線上服務(wù)器環(huán)境使用。
示例一
統(tǒng)計(jì)方法耗時(shí)
classes java -agentlib:hprof=cpu=times,interval=10 com.kkb.example.HprofTest
Dumping CPU usage by timing methods ... done.
classes vim java.hprof.txt
示例二
生成跟蹤點(diǎn)類所占內(nèi)存百分比
classes java -agentlib:hprof=heap=sites com.kkb.example.HprofTest
Dumping allocation sites ... done.
classes vim java.hprof.txt
5.8 jconsole
Jconsole:Java Monitoring and Management Console初家,Java 5引入偎窘,一個內(nèi)置 Java 性能分析器,可以從命令行或在 GUI shell 中運(yùn)行笤成。您可以輕松地使用 JConsole來監(jiān)控 Java 應(yīng)用程序性能和跟蹤Java 中的代碼评架。
5.8.1 如何啟動JConsole
如果是從命令行啟動,使 JDK 在 PATH 上炕泳,運(yùn)行 jconsole 即可。
如果從 GUI shell 啟動上祈,找到 JDK 安裝路徑培遵,打開 bin 文件夾浙芙,雙擊 jconsole 。
當(dāng)分析工具彈出時(shí)(取決于正在運(yùn)行的 Java 版本以及正在運(yùn)行的 Java 程序數(shù)量)籽腕,可能會出現(xiàn)一個對話框嗡呼,要求輸入一個進(jìn)程的 URL 來連接,也可能列出許多不同的本地 Java 進(jìn)程(有時(shí)包含JConsole 進(jìn)程本身)來連接皇耗。
如下圖所示:想分析哪個程序就雙擊哪個進(jìn)程南窗。
5.8.2 如何設(shè)置JAVA程序運(yùn)行時(shí)可以被JConsolse連接分析
本地程序(相對于開啟JConsole的計(jì)算機(jī)),無需設(shè)置任何參數(shù)就可以被本地開啟的JConsole連接(Java SE 6開始無需設(shè)置郎楼,之前還是需要設(shè)置運(yùn)行時(shí)參數(shù) -Dcom.sun.management.jmxremote )
JConsole如何連接遠(yuǎn)程機(jī)器的JAVA程序万伤?
jconsole 192.168.0.1:8999
也可以在已經(jīng)打開的JConsole界面操作,連接?新建連接?選擇遠(yuǎn)程進(jìn)程?輸入遠(yuǎn)程主機(jī)IP和端口號?點(diǎn)擊“連接”呜袁,如下圖
5.8.3 示例
示例一
進(jìn)入視圖后包括這六個標(biāo)簽:
- Overview: 顯示有關(guān)JVM和監(jiān)視值的概述信息
- Memory: 顯示內(nèi)存使用信息
- Threads: 顯示線程使用信息
- Classes: 顯示類裝載信息
- VM Summary:顯示java VM信息
-
MBeans: 顯示 MBeans
上圖描述有我們需要的信息敌买,同時(shí)點(diǎn)擊右鍵可以保存數(shù)據(jù)到CSV文件。
內(nèi)存頁簽相對于可視化的jstat 命令阶界,用于監(jiān)視受收集器管理的虛擬機(jī)內(nèi)存虹钮。
6 JVM參數(shù)
在JVM調(diào)整過程中,主要是對JVM參數(shù)做的調(diào)整膘融,以下我們介紹主要參數(shù)芙粱。JVM參數(shù)有很多,其實(shí)我們直接使用默認(rèn)的JVM參數(shù)氧映,不去修改都可以滿足大多數(shù)情況宅倒。但是如果你想在有限的硬件資源下,部署的系統(tǒng)達(dá)到最大的運(yùn)行效率屯耸,那么進(jìn)行相關(guān)的JVM參數(shù)設(shè)置是必不可少的拐迁。
JVM參數(shù)主要分為以下三種:標(biāo)準(zhǔn)參數(shù)、非標(biāo)準(zhǔn)參數(shù)疗绣、不穩(wěn)定參數(shù)线召。
6.1 標(biāo)準(zhǔn)參數(shù)
標(biāo)準(zhǔn)參數(shù),顧名思義多矮,標(biāo)準(zhǔn)參數(shù)中包括功能以及輸出的結(jié)果都是很穩(wěn)定的缓淹,基本上不會隨著JVM版本的變化而變化。
標(biāo)準(zhǔn)參數(shù)以-開頭塔逃,如:java -version讯壶、java -jar等,通過java -help可以查詢所有的標(biāo)準(zhǔn)參數(shù)湾盗,-help 也是?個標(biāo)準(zhǔn)參數(shù)伏蚊。
6.2 非標(biāo)準(zhǔn)參數(shù)
非標(biāo)準(zhǔn)參數(shù)以-X開頭,是標(biāo)準(zhǔn)參數(shù)的擴(kuò)展格粪。對應(yīng)前面講的標(biāo)準(zhǔn)化參數(shù)躏吊,這是非標(biāo)準(zhǔn)化參數(shù)氛改。表示在將來的JVM版本中可能會發(fā)生改變,但是這類以-X開始的參數(shù)變化的比較小比伏。
我們可以通過 Java -X 命令來檢索所有-X 參數(shù)胜卤。
我們可以通過設(shè)置非標(biāo)準(zhǔn)參數(shù)來配置堆的內(nèi)存分配,常用的非標(biāo)準(zhǔn)參數(shù)有:
- -Xmn新生代內(nèi)存的大小赁项,包括Eden區(qū)和兩個Survivor區(qū)的總和葛躏,寫法如:-Xmn1024,-Xmn1024k悠菜,-Xmn1024m舰攒,-Xmn1g 。
- -Xms堆內(nèi)存的最小值李剖,默認(rèn)值是總內(nèi)存/64(且小于1G)芒率。默認(rèn)情況下,當(dāng)堆中可用內(nèi)存小于40%(這個值可以用-XX: MinHeapFreeRatio 調(diào)整篙顺,如-X:MinHeapFreeRatio=30)時(shí)偶芍,堆內(nèi)存會開始增加,?直增加到-Xmx的大小德玫。
- -Xmx堆內(nèi)存的最大值匪蟀,默認(rèn)值是總內(nèi)存/4(且小于1G)。默認(rèn)情況下宰僧,當(dāng)堆中可用內(nèi)存大于70%(這個值可以用-XX: MaxHeapFreeRatio調(diào)整材彪,如-X:MaxHeapFreeRatio =80)時(shí),堆內(nèi)存會開始減少琴儿,一直減小到-Xms的大小段化。
如果Xms和Xmx都不設(shè)置,則兩者大小會相同 - -Xss每個線程的棧內(nèi)存造成,默認(rèn)1M显熏,?般來說是不需要改的。
- -Xrs減少JVM對操作系統(tǒng)信號的使用晒屎。
- -Xprof跟蹤正運(yùn)行的程序喘蟆,并將跟蹤數(shù)據(jù)在標(biāo)準(zhǔn)輸出輸出。適合于開發(fā)環(huán)境調(diào)試鼓鲁。
- -Xnoclassgc關(guān)閉針對class的gc功能蕴轨。因?yàn)槠渥柚羶?nèi)存回收,所以可能會導(dǎo)致OutOfMemoryError錯誤骇吭,慎用橙弱。
- -Xincgc開啟增量gc(默認(rèn)為關(guān)閉)。這有助于減少長時(shí)間GC時(shí)應(yīng)用程序出現(xiàn)的停頓,但由于可能和應(yīng)用程序并發(fā)執(zhí)行膘螟,所以會降低CPU對應(yīng)用的處理能力成福。
- -Xloggc:file與-verbose:gc功能類似碾局,只是將每次GC事件的相關(guān)情況記錄到一個文件中荆残,文件的位置最好在本地,以避免網(wǎng)絡(luò)的潛在問題净当。
6.3 不穩(wěn)定參數(shù)
這是我們?nèi)粘i_發(fā)中接觸到最多的參數(shù)類型内斯。這也是非標(biāo)準(zhǔn)化參數(shù),相對來說不穩(wěn)定像啼,隨著JVM版本的變化可能會發(fā)生變化俘闯,主要用于JVM調(diào)優(yōu)和debug。
不穩(wěn)定參數(shù)以-XX 開頭忽冻,此類參數(shù)的設(shè)置很容易引起JVM 性能上的差異真朗,使JVM存在極大的不穩(wěn)定性。如果此類參數(shù)設(shè)置合理將大大提高JVM的性能及穩(wěn)定性僧诚。
不穩(wěn)定參數(shù)分為三類:
- 性能參數(shù):用于JVM的性能調(diào)優(yōu)和內(nèi)存分配控制遮婶,如內(nèi)存大小的設(shè)置
- 行為參數(shù):用于改變JVM的基礎(chǔ)行為,如GC的方式和算法的選擇
- 調(diào)試參數(shù):用于監(jiān)控湖笨、打印旗扑、輸出jvm的信息
不穩(wěn)定參數(shù)語法規(guī)則:
- 布爾類型參數(shù)值:
- -XX:+
- -XX:-
示例:-XX:+UseG1GC,表示啟用G1垃圾收集器
- 數(shù)字類型參數(shù)值:
-XX:
示例:-XX:MaxGCPauseMillis=500 慈省,表示設(shè)置GC的最大停頓時(shí)間是500ms - 字符串類型參數(shù)值:
-XX:
示例:-XX:HeapDumpPath=./dump.core
6.4 常?參數(shù)
–Xms4g -Xmx4g –Xmn1200m –Xss512k
-XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15
-XX:PermSize=100m -XX:MaxPermSize=256m
-XX:MaxDirectMemorySize=1G -XX:+DisableExplicitGC
參數(shù)解析:
- -Xms4g:初始化堆內(nèi)存大小為4GB臀防,ms是memory start的簡稱,等價(jià)于-XX:InitialHeapSize边败。
- -Xmx4g:堆內(nèi)存最大值為4GB袱衷,mx是memory max的簡稱,等價(jià)于-XX:MaxHeapSize笑窜。
- -Xmn1200m:設(shè)置年輕代大小為1200MB致燥。增大年輕代后,將會減小老年代大小怖侦。此值對系統(tǒng)性能影響較大篡悟,Sun官方推薦配置為整個堆的3/8。
- -Xss512k:設(shè)置每個線程的堆棧大小匾寝。JDK5.0以后每個線程堆棧大小為1MB搬葬,以前每個線程堆棧大小為256K。應(yīng)根據(jù)應(yīng)用線程所需內(nèi)存大小進(jìn)行調(diào)整艳悔。在相同物理內(nèi)存下急凰,減小這個值能生成更多的線程。但是操作系統(tǒng)對一個進(jìn)程內(nèi)的線程數(shù)還是有限制的,不能無限生成抡锈,經(jīng)驗(yàn)值在3000~5000左右疾忍。
- -XX:NewRatio=4:設(shè)置年輕代(包括Eden和兩個Survivor區(qū))與老年代的比值(除去持久代)。設(shè)置為4床三,則年輕代與老年代所占比值為1:4一罩,年輕代占整個堆棧的1/5
- -XX:SurvivorRatio=8:設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的大小比值。設(shè)置為8撇簿,則兩個Survivor區(qū)與?個Eden區(qū)的比值為2:8聂渊,?個Survivor區(qū)占整個年輕代的1/10
- -XX:PermSize=100m:初始化永久代大小為100MB。
- -XX:MaxPermSize=256m:設(shè)置持久代大小為256MB四瘫。
- -XX:MaxTenuringThreshold=15:設(shè)置垃圾最大年齡汉嗽。如果設(shè)置為0的話,則年輕代對象不經(jīng)過Survivor區(qū)找蜜,直接進(jìn)入老年代饼暑。對于老年代比較多的應(yīng)用,可以提高效率洗做。如果將此值設(shè)置為?個較大值弓叛,則年輕代對象會在Survivor區(qū)進(jìn)行多次復(fù)制,這樣可以增加對象在年輕代的存活時(shí)間竭望,增加在年輕代即被回收的概率邪码。
- -XX:MaxDirectMemorySize=1G:直接內(nèi)存。報(bào)java.lang.OutOfMemoryError: Direct buffermemory異骋澹可以上調(diào)這個值闭专。
- -XX:+DisableExplicitGC:禁止運(yùn)行期顯式地調(diào)用System.gc()來觸發(fā)fulll GC。
注意: Java RMI的定時(shí)GC觸發(fā)機(jī)制可通過配置-Dsun.rmi.dgc.server.gcInterval=86400來控制觸發(fā)的時(shí)間旧烧。 - -XX:CMSInitiatingOccupancyFraction=60:老年代內(nèi)存回收閾值影钉,默認(rèn)值為68。
- -XX:ConcGCThreads=4:CMS垃圾回收器并行線程線掘剪,推薦值為CPU核心數(shù)平委。
- -XX:ParallelGCThreads=8:新生代并行收集器的線程數(shù)。
- -XX:CMSMaxAbortablePrecleanTime=500:當(dāng)abortable-preclean預(yù)清理階段執(zhí)行達(dá)到這個時(shí)間時(shí)就會結(jié)束夺谁。
新生代廉赔、老年代、永久代的參數(shù)匾鸥,如果不進(jìn)性指定蜡塌,虛擬機(jī)會子動選擇合適的值,同時(shí)也會基于系統(tǒng)的開銷自動調(diào)整勿负。
6.4.1 -XX:+PrintFlagsInitial馏艾、-XX:+PrintFlagsFinal
Java 6(update 21oder 21之后)版本, HotSpot JVM 提供給了兩個新的參數(shù),在JVM啟動后琅摩,在命令行中可以輸出所有XX參數(shù)和值铁孵。
-XX:+PrintFlagsInitial:查看初始值
-XX:+PrintFlagsFinal:查看最終值(初始值可能被修改掉)
讓我們現(xiàn)在就了解一下新參數(shù)的輸出。以 -client 作為參數(shù)的 -XX:+ PrintFlagsFinal 的結(jié)果是一個按字母排序的590個參數(shù)表格(注意房资,每個release版本參數(shù)的數(shù)量會不一樣)
表格的每一行包括五列蜕劝,來表示一個XX參數(shù)。第一列表示參數(shù)的數(shù)據(jù)類型志膀,第二列是名稱熙宇,第四列為值磅网,第五列是參數(shù)的類別岳颇。第三列”=”表示第四列是參數(shù)的默認(rèn)值宏赘,而”:=” 表明了參數(shù)被用戶或者JVM賦值了。
如果我們只想看下所有XX參數(shù)的默認(rèn)值戳稽,能夠用一個相關(guān)的參數(shù),-XX:+PrintFlagsInitial 期升。 用 -XX:+PrintFlagsInitial , 只是展示了第三列為“=”的數(shù)據(jù)(也包括那些被設(shè)置其他值的參數(shù))惊奇。
然而,注意當(dāng)與-XX:+PrintFlagsFinal 對比的時(shí)候播赁,一些參數(shù)會丟失颂郎,大概因?yàn)檫@些參數(shù)是動態(tài)創(chuàng)建的。
6.4.2 -XX:+PrintCommandLineFlags
讓我們看下這個參數(shù)容为,事實(shí)上這個參數(shù)非常有用: -XX:+PrintCommandLineFlags 乓序。這個參數(shù)讓JVM打印出那些已經(jīng)被用戶或者JVM設(shè)置過的詳細(xì)的XX參數(shù)的名稱和值。
換句話說坎背,它列舉出 -XX:+PrintFlagsFinal的結(jié)果中第三列有":="的參數(shù)替劈。以這種方式, 我們可以用-XX:+PrintCommandLineFlags作為快捷方式來查看修改過的參數(shù)得滤≡上祝看下面的例子。
現(xiàn)在如果我們每次啟動java 程序的時(shí)候設(shè)置 -XX:+PrintCommandLineFlags 并且輸出到日志文件上懂更,這樣會記錄下我們設(shè)置的JVM 參數(shù)對應(yīng)用程序性能的影響眨业。
6.4.3 GC日志相關(guān)
設(shè)置JVM GC格式日志的主要參數(shù)包括如下8個:
- -XX:+PrintGC 輸出簡要GC日志
- -XX:+PrintGCDetails 輸出詳細(xì)GC日志
- -Xloggc:gc.log 輸出GC日志到文件
- -XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以JVM啟動到當(dāng)期的總時(shí)長的時(shí)間戳形式)
- -XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2020-04-26T21:53:59.234+0800)
- -XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息
- -verbose:gc : 在JDK 8中沮协,-verbose:gc是-XX:+PrintGC一個別稱龄捡,日志格式等價(jià)于:-XX:+PrintGC。不過在JDK 9中 -XX:+PrintGC被標(biāo)記為deprecated皂股。
-verbose:gc是一個標(biāo)準(zhǔn)的選項(xiàng)墅茉,-XX:+PrintGC是一個實(shí)驗(yàn)的選項(xiàng),建議使用-verbose:gc 替代-XX:+PrintGC - -XX:+PrintReferenceGC 打印年輕代各個引用的數(shù)量以及時(shí)長
開啟GC日志
多種方法都能開啟GC的日志功能,其中包括:使用-verbose:gc或-XX:+PrintGC這兩個標(biāo)志中的任意一個能創(chuàng)建基本的GC日志(這兩個日志標(biāo)志實(shí)際上互為別名就斤,默認(rèn)情況下的GC日志功能是關(guān)閉的)使用-XX:+PrintGCDetails標(biāo)志會創(chuàng)建更詳細(xì)的GC日志悍募。
推薦使用-XX:+PrintGCDetails標(biāo)志(這個標(biāo)志默認(rèn)情況下也是關(guān)閉的);通常情況下使用基本的GC日志很難診斷垃圾回收時(shí)發(fā)生的問題洋机。
開啟GC時(shí)間提示
除了使用詳細(xì)的GC日志坠宴,我們還推薦使用-XX:+PrintGCTimeStamps或者-XX:+PrintGCDateStamps,便于我們更精確地判斷幾次GC操作之間的時(shí)間绷旗。這兩個參數(shù)之間的差別在于時(shí)間戳是相對于0(依據(jù)JVM啟動的時(shí)間)的值喜鼓,而日期戳(date stamp)是實(shí)際的日期字符串。由于日期戳需要進(jìn)性格式化衔肢,所以它的效率可能會受輕微的影響庄岖,不過這種操作并不頻繁,它造成的影響也很難被我們感知角骤。
指定GC日志路徑
默認(rèn)情況下GC日志直接輸出到標(biāo)準(zhǔn)輸出隅忿,不過使用-Xloggc:filename標(biāo)志也能修改輸出到某個文件。除了顯式地使用-PrintGCDetails標(biāo)志邦尊,否則使用-Xloggc會自動地開啟基本日志模式背桐。
使用日志循環(huán)(Log rotation)標(biāo)志可以限制保存在GC日志中的數(shù)據(jù)量;對于需要長時(shí)間運(yùn)行的服務(wù)器而言蝉揍,這是一個非常有用的標(biāo)志链峭,否則累積幾個月的數(shù)據(jù)很可能會耗盡服務(wù)器的磁盤。
開啟日志滾動輸出
通過-XX:+UseGCLogfileRotation -XX:NumberOfGCLogfiles=N -XX:GCLogfileSize=N標(biāo)志可以控制日志文件的循環(huán)又沾。
默認(rèn)情況下弊仪,UseGCLogfileRotation標(biāo)志是關(guān)閉的。它負(fù)責(zé)打開或關(guān)閉GC日志滾動記錄功能的捍掺。要求必須設(shè)置 -Xloggc參數(shù)開啟UseGCLogfileRotation標(biāo)志后撼短,默認(rèn)的文件數(shù)目是0(意味著不作任何限制),默認(rèn)的日志文件大小是0(同樣也是不作任何限制)挺勿。因此曲横,為了讓日志循環(huán)功能真正生效,我們必須為所有這些標(biāo)志設(shè)定值不瓶。
需要注意的是:
- 設(shè)置滾動日志文件的大小禾嫉,必須大于8k。當(dāng)前寫日志文件大小超過該參數(shù)值時(shí)蚊丐,日志將寫入下一個文件
- 設(shè)置滾動日志文件的個數(shù)熙参,必須大于等于1
- 必須設(shè)置 -Xloggc 參數(shù)
開啟語句
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/home/hadoop/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=512k
其他有用參數(shù)
-XX:+PrintGCApplicationStoppedTime 打印GC造成應(yīng)用暫停的時(shí)間
-XX:+PrintTenuringDistribution 在每次新生代 young GC時(shí),輸出幸存區(qū)中對象的年齡分布
日志含義
6.4.4 -XX:CMSFullGCsBeforeCompaction
CMSFullGCsBeforeCompaction 說的是,在上一次CMS并發(fā)GC執(zhí)行過后麦备,到底還要再執(zhí)行多少次full GC才會做壓縮孽椰。默認(rèn)是0昭娩,也就是在默認(rèn)配置下每次CMS GC頂不住了而要轉(zhuǎn)入full GC的時(shí)候都會做壓縮。 如果把CMSFullGCsBeforeCompaction配置為10黍匾,就會讓上面說的第一個條件變成每隔10次真正的full GC才做一次壓縮(而不是每10次CMS并發(fā)GC就做一次壓縮栏渺,目前VM里沒有這樣的參數(shù))。這會使full GC更少做壓縮锐涯,也就更容易使CMS的old gen受碎片化問題的困擾磕诊。 本來這個參數(shù)就是用來配置降低full GC壓縮的頻率,以期減少某些full GC的暫停時(shí)間纹腌。CMS回退到full GC時(shí)用的算法是mark-sweep-compact霎终,但compaction是可選的,不做的話碎片化會嚴(yán)重些但這次full GC的暫停時(shí)間會短些升薯。這是個取舍莱褒。
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=10
兩個參數(shù)必須同時(shí)使用才能生效。
6.4.5 -XX:HeapDumpPath
堆內(nèi)存出現(xiàn)OOM的概率是所有內(nèi)存耗盡異常中最高的覆劈,出錯時(shí)的堆內(nèi)信息對解決問題非常有幫助保礼,所以給JVM設(shè)置這個參數(shù)(-XX:+HeapDumpOnOutOfMemoryError),讓JVM遇到OOM異常時(shí)能輸出堆內(nèi)信息责语,并通過(-XX:+HeapDumpPath)參數(shù)設(shè)置堆內(nèi)存溢出快照輸出的文件地址,這對于特別是對相隔數(shù)月才出現(xiàn)的OOM異常來說尤為重要目派。
這兩個參數(shù)通常配套使用:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
6.4.6 -XX:OnOutOfMemoryError
-XX:OnOutOfMemoryError=
"/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/binjconsole"
表示發(fā)生OOM后坤候,運(yùn)行jconsole程序。這里可以不用加“”企蹭,因?yàn)閖console.exe路徑Program Files含有空格白筹。
利用這個參數(shù),我們可以在系統(tǒng)OOM后谅摄,自定義一個腳本徒河,可以用來發(fā)送郵件告警信息,可以用來重啟系統(tǒng)等等送漠。
6.4.7 XX:InitialCodeCacheSize
JVM一個有趣的顽照,但往往被忽視的內(nèi)存區(qū)域是“代碼緩存”,它是用來存儲已編譯方法生成的本地代碼闽寡。代碼緩存確實(shí)很少引起性能問題代兵,但是一旦發(fā)生其影響可能是毀滅性的。如果代碼緩存被占滿爷狈,JVM會打印出一條警告消息植影,并切換到interpreted-only 模式:JIT編譯器被停用,字節(jié)碼將不再會被編譯成機(jī)器碼涎永。因此思币,應(yīng)用程序?qū)⒗^續(xù)運(yùn)行鹿响,但運(yùn)行速度會降低一個數(shù)量級,直到有人注意到這個問題谷饿。
就像其他內(nèi)存區(qū)域一樣抢野,我們可以自定義代碼緩存的大小。相關(guān)的參數(shù)是-XX:InitialCodeCacheSize 和-
XX:ReservedCodeCacheSize各墨,它們的參數(shù)和上面介紹的參數(shù)一樣指孤,都是字節(jié)值。
6.4.8 -XX:+UseCodeCacheFlushing
如果代碼緩存不斷增長贬堵,例如恃轩,因?yàn)闊岵渴鹨鸬膬?nèi)存泄漏,那么提高代碼的緩存大小只會延緩其發(fā)生溢出黎做。
為了避免這種情況的發(fā)生叉跛,我們可以嘗試一個有趣的新參數(shù):當(dāng)代碼緩存被填滿時(shí)讓JVM放棄一些編譯代碼。通過使用-XX:+UseCodeCacheFlushing 這個參數(shù)蒸殿,我們至少可以避免當(dāng)代碼緩存被填滿的時(shí)候JVM切換到interpreted-only 模式筷厘。
不過,我仍建議盡快解決代碼緩存問題發(fā)生的根本原因宏所,如找出內(nèi)存泄漏并修復(fù)它酥艳。