JVM Heap dump和Thread dump
1、記憶體Heap Dump檔案抓取
heap dump記錄了JVM中堆記憶體執行的情況。
- XX:+HeapDumpOnOutOfMemoryError
應用啟動時配置引數,當OutOfMemoryError發生時自動生成 Heap Dump 檔案。這可是一個非常有用的引數,因為當你需要分析Java記憶體使用情況時,往往是在OOM(OutOfMemoryError)發生時。-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=data
注意:JVM 生成 Heap Dump 的時候,虛擬機器是暫停一切服務的。如果是線上系統執行 Heap Dump 時需要注意。
2、執行緒Thread Dump檔案抓取
Thread dump 檔案記錄了當時JVM中執行緒執行的情況,Thread dumps 能幫助我們判斷 CPU 峰值、死鎖、記憶體異常、應用反應遲鈍、響應時間變長和其他系統問題。
- kill -3
出於安全方面的考慮,生產環境有時候只包含JRE環境,這時jdk下的工具就不能用了kill -3 <pid> kill -3 37320
3、GUI分析工具——JVisualVM/JConsole
-
JConsole :
JDK提供的一個基於GUI檢視JVM系統資訊的工具,既可以管理本地的JVM,也可以管理遠端的JVM -
JVisualVM:
JDK提供的可以從本地或者遠端執行的 JVM 裡抓取 dump 檔案。
https://blog.csdn.net/moneyshi/article/details/81511687
JVisualVM/JConsole雖然用起來很方便,但是如果要連線遠端機器上的jvm,則遠端機器上的jvm需要加引數(本地的不需要),所以生產環境上我們通常是不會直接用這兩個工具的,這時就需要用到命令列工具了。
4、命令列工具
4.1 jmap
Jmap是一個JDK提供的可以輸出所有記憶體中物件的工具,甚至可以將VM 中的heap,以二進位制輸出成文字。打印出某個java程序(使用pid)記憶體內的,所有‘物件’的情況(如:產生那些物件,及其數量)。
常用命令
-
jmap -heap pid
檢視程序堆記憶體詳細資訊,包括使用的GC演算法、堆配置引數和各代中堆記憶體使用情況 -
jmap -histo[:live] pid
檢視java堆中物件的相關資訊,包含數量以及佔用的空間大小,如果帶上live則只統計活物件 -
jmap -permstat pid
列印程序的類載入器和類載入器載入的持久代物件資訊,輸出:類載入器名稱、物件是否存活(不可靠)、物件地址、父類載入器、已載入的類大小等資訊
- jmap -dump:live,format=b,file=heap-dump.bin <pid>
生成Heap Dump到檔案,其中的pid是JVM程序的id,heap-dump.bin是生成的檔名稱,在執行命令的目錄下面,可以把生成的dump檔案載入到GUI工具中檢視
4.2 jstack——jdk包含
jstack主要用來檢視某個Java程序內的執行緒堆疊資訊,jstack可以定位到執行緒堆疊,根據堆疊資訊我們可以定位到具體程式碼,所以它在JVM效能調優中使用得非常多
-
jstack -F pid
檢查是否有死鎖 -
jstack -l pid
打印出額外的鎖資訊,在發生死鎖時可以用jstack -l pid來觀察鎖持有情況 -
jstack -l 37320 > /opt/tmp/threadDump.txt
儲存 dump 資訊到檔案 -
使用例項:系統cpu消耗比較高,那我們怎麼定位到是哪裡出問題?
- 先找出java程序ID;
ps -ef | grep flybird —— 21711 - 找出該程序內最耗費CPU的執行緒;
top -Hp pid ——21742 - 輸出程序21711的堆疊資訊,並且查詢到具體的執行緒id;
jstack 21711 | grep 54ee
注意:54ee是執行緒id 21742的16進位制值
4.3 jstat(JVM統計監測工具)
-
jstat -gc 91328
檢視jvm垃圾回收情況,包括FGC、YGC的總次數和累計耗時 -
jstat -gcutil 91328
功能和gc 一樣,但是是百分比的形式,讀取更友好 -
jstat -gccapacity 91328
讀取各個代區的當前容量、最大容量、當前使用量等資訊
5、調優
- -Xms:設定初始分配大小,預設為實體記憶體的“1/64”;
- -Xmx:最大分配記憶體,預設為實體記憶體的“1/4”;
- -Xss規定了每個執行緒堆疊的大小。一般情況下256K是足夠了。太大了影響此程序中併發執行緒數大小;
在整個堆記憶體的調整策略之中,有經驗的人基本只會調整兩個引數:“-Xmx”(最大記憶體)、“-Xms”(初始化記憶體)。如果要取得這些記憶體的整體資訊,直接利用Runtime類即可;
在很多情況下,-Xms和-Xmx設定成一樣的。這麼設定,是因為當Heap不夠用時,會發生記憶體抖動,影響程式執行穩定性。
通過 ps -ef | grep java 可以查詢到啟動時設定的這些引數,如下
$ ps -ef | grep java
user_00 1689 1 1 Oct19 ? 17:39:05 /usr/local/services/elasticsearch-7.2.1/jdk/bin/java
-Xms2g
-Xmx2g
-Xss1m
-XX:+UseG1GC
-XX:MaxTenuringThreshold=15
-XX:MaxGCPauseMillis=3000
-XX:InitiatingHeapOccupancyPercent=75
-Des.networkaddress.cache.ttl=60
-Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true
-Djava.io.tmpdir=/tmp/elasticsearch-2105800618487179719
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log
-Xlog:gc*,gc+age=trace,
safepoint:file=/data/elasticsearch/logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m
-Djava.locale.providers=COMPAT -Dio.netty.allocator.type=pooled
-XX:MaxDirectMemorySize=1073741824
-Des.path.home=/usr/local/services/elasticsearch-7.2.1
-Des.path.conf=/usr/local/services/elasticsearch-7.2.1/config
-Des.distribution.flavor=default -Des.distribution.type=tar
-Des.bundled_jdk=true -cp /usr/local/services/elasticsearch-7.2.1/lib/* org.elasticsearch.bootstrap.Elasticsearch -p /usr/local/services/elasticsearch-7.2.1/logs/elasticsearch.pid --quiet