1. 程式人生 > 實用技巧 >JVM Heap dump和Thread dump

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://www.cnblogs.com/xifengxiaoma/p/9402497.html

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消耗比較高,那我們怎麼定位到是哪裡出問題?

  1. 先找出java程序ID;
    ps -ef | grep flybird —— 21711
  2. 找出該程序內最耗費CPU的執行緒;
    top -Hp pid ——21742
  3. 輸出程序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