JVM調(diào)優(yōu)

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)用
01.png

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 示例

02.png

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
03.png
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
04.png
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輸出的堆文件

05.png

這樣就啟動起來了一個簡易的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 示例

示例一

06.png

示例二
將指定進(jìn)程的當(dāng)前堆棧情況記錄到某個?件中

07.png

示例三
統(tǒng)計(jì)線程數(shù)

08.png

示例四
檢測死鎖

09.png

10.png

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
11.png

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
12.png

示例二

生成跟蹤點(diǎn)類所占內(nèi)存百分比

classes java -agentlib:hprof=heap=sites com.kkb.example.HprofTest
Dumping allocation sites ... done.
classes vim java.hprof.txt
13.png

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)程南窗。

14.png

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)擊“連接”呜袁,如下圖

15.png

5.8.3 示例

示例一
進(jìn)入視圖后包括這六個標(biāo)簽:

  • Overview: 顯示有關(guān)JVM和監(jiān)視值的概述信息
  • Memory: 顯示內(nèi)存使用信息
  • Threads: 顯示線程使用信息
  • Classes: 顯示類裝載信息
  • VM Summary:顯示java VM信息
  • MBeans: 顯示 MBeans


    16.png

上圖描述有我們需要的信息敌买,同時(shí)點(diǎn)擊右鍵可以保存數(shù)據(jù)到CSV文件。

內(nèi)存頁簽相對于可視化的jstat 命令阶界,用于監(jiān)視受收集器管理的虛擬機(jī)內(nèi)存虹钮。

17.png

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ù)量會不一樣)

18.png

表格的每一行包括五列蜕劝,來表示一個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)建的。

19.png

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ù)得滤≡上祝看下面的例子。

20.png

現(xiàn)在如果我們每次啟動java 程序的時(shí)候設(shè)置 -XX:+PrintCommandLineFlags 并且輸出到日志文件上懂更,這樣會記錄下我們設(shè)置的JVM 參數(shù)對應(yīng)用程序性能的影響眨业。

6.4.3 GC日志相關(guān)

設(shè)置JVM GC格式日志的主要參數(shù)包括如下8個:

  1. -XX:+PrintGC 輸出簡要GC日志
  2. -XX:+PrintGCDetails 輸出詳細(xì)GC日志
  3. -Xloggc:gc.log 輸出GC日志到文件
  4. -XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以JVM啟動到當(dāng)期的總時(shí)長的時(shí)間戳形式)
  5. -XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2020-04-26T21:53:59.234+0800)
  6. -XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息
  7. -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
  8. -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ū)中對象的年齡分布

日志含義

21.png
22.png

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ù)它酥艳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市爬骤,隨后出現(xiàn)的幾起案子充石,更是在濱河造成了極大的恐慌,老刑警劉巖霞玄,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骤铃,死亡現(xiàn)場離奇詭異,居然都是意外死亡坷剧,警方通過查閱死者的電腦和手機(jī)惰爬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惫企,“玉大人撕瞧,你說我怎么就攤上這事⊙湃危” “怎么了风范?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沪么。 經(jīng)常有香客問我硼婿,道長,這世上最難降的妖魔是什么禽车? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任寇漫,我火速辦了婚禮刊殉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘州胳。我一直安慰自己记焊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布栓撞。 她就那樣靜靜地躺著遍膜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓤湘。 梳的紋絲不亂的頭發(fā)上瓢颅,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音弛说,去河邊找鬼挽懦。 笑死,一個胖子當(dāng)著我的面吹牛木人,可吹牛的內(nèi)容都是我干的信柿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼醒第,長吁一口氣:“原來是場噩夢啊……” “哼渔嚷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淘讥,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤圃伶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蒲列,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搀罢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年蝗岖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榔至。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡抵赢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唧取,到底是詐尸還是另有隱情铅鲤,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布枫弟,位于F島的核電站邢享,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淡诗。R本人自食惡果不足惜骇塘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一伊履、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧款违,春花似錦唐瀑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赠尾,卻和暖如春力穗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萍虽。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工睛廊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杉编。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓超全,卻偏偏與公主長得像,于是被迫代替她去往敵國和親邓馒。 傳聞我的和親對象是個殘疾皇子嘶朱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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

  • JVM 調(diào)優(yōu)概述 性能定義 吞吐量 - 指不考慮 GC 引起的停頓時(shí)間或內(nèi)存消耗,垃圾收集器能支撐應(yīng)用達(dá)到的最高性...
    裘馬輕狂大帥閱讀 246評論 0 1
  • JVM 調(diào)優(yōu)概述 性能定義 吞吐量 - 指不考慮 GC 引起的停頓時(shí)間或內(nèi)存消耗光酣,垃圾收集器能支撐應(yīng)用達(dá)到的最高性...
    裘馬輕狂大帥閱讀 255評論 0 1
  • 運(yùn)用jvm自帶的命令可以方便的在生產(chǎn)監(jiān)控和打印堆棧的日志信息幫忙我們來定位問題疏遏!雖然jvm調(diào)優(yōu)成熟的工具已經(jīng)有很多...
    王知無閱讀 685評論 1 1
  • 何時(shí)進(jìn)行JVM調(diào)優(yōu) Heap內(nèi)存(老年代)持續(xù)上漲達(dá)到設(shè)置的最大內(nèi)存值; Full GC 次數(shù)頻繁救军; GC 停頓時(shí)...
    請不要問我是誰閱讀 248評論 0 0
  • JVM調(diào)優(yōu)(一) 本片內(nèi)容 我們?yōu)槭裁匆獙VM優(yōu)化 掌握jvm的運(yùn)行參數(shù)以及參數(shù)的設(shè)置 掌握jvm的內(nèi)存模型(堆...
    SuBHFeng閱讀 190評論 0 0