jmap:導出內存映像文件&內存使用情況
基本情況
jmap(JVM Memory Map):一方法獲取dump文件(堆轉儲快照文件,二進制文件),還可以獲取目標Java進程的內存相關信息,包括Java堆各區域的使用情況、堆中對象的統計信息、類加載信息
基本語法
jmap [option] (to connect to running process) jmap [option] <executable (to connect to a core file) jmap [option] [server_id@] (to connect to remote debug server) option包括下表:
生成Java堆轉儲快照:dump文件 特別的:-dump:live只保存堆中的存活對象
輸出整個堆空間的詳細信息,包括GC的使用,堆配置信息以及內存使用信息
輸出堆空間中對象的統計信息,包括類,實例數量和合計容量
以ClassLoader為統計口徑輸出永久代的內存狀態信息
顯示在F-Queue中等待Finalizer線程執行finalize方法的對象
當虛擬機進程對-dump選項沒有任何響應時,強制執行生成dump文件
導出內存映射文件
將堆中所有存活對象導出至一個文件之中 Heap Dump又叫堆存儲文件,指一個Java進程在某個時間點的內存快照,Heap Dump在觸發內存快照的時候會保存此該的信息
All Objects All Classes Garbage Collection Roots Thread Stacks and Local Variables ①通常在寫Heap Dump文件前會觸發一次Full GC,所以heap dump文件里保存的都是Full GC后留下的對象信息 ②由于生成dump文件比較耗時,需要耐心等待,尤其大內存鏡像生成dump文件,則需要耗費更長的時間來完成
jmap -dump:format=b,file=<filename.hprof> 注:format=b表示采用圖形化工具能打開對應的hprof文件 jmap -dump:live,format=b,file=<filename.hprof>
當程序發生OOM退出系統時,一些瞬時停止都隨著程序的終止而消失,而重現OOM問題往往比較困難或者耗時,此時若能在OOM時,自動導出dump文件就顯得很重要 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<filename.hprof>
顯示堆內存相關信息
-heap pid:程序運行時 -histo pid
其它作用
-pemstat pid :查看系統的ClassLoader信息–linux環境下 -finzlizerinfo:查看堆積在finalizer隊列中的對象–linux環境下
總結
由于jmap將訪問堆中的所有對象,為了保證在此過程中不被應用線程干擾,jmap需要借助安全點機制 ,讓所有線程停留在不改變堆中數據的狀態,由jmap導出的堆快照必定是安全點位置的,這可能導致基于該堆快照的分析結果存在偏差 舉個例子:假設在編譯生成的機器碼中,某些對象的生命周期在兩個安全點之間,那么:live選項將無法探知到這些對象 如果某個線程長時間無法跑到安全點,jmap將一直等下去,與前面的jstat不同,垃圾回收器會主動將jstat所需要的摘要數據保存至固定位置之中,而jstat只需直接讀取即可
jhat(JVM Heap Analysis Tool)
Sun JDK提供了jhat與jmap命令搭配使用,用于分析jmap生成的heap dump文件,jhat內置了一個微型的HTTP/HTML服務器,生成dump文件的分析結果后,用戶可以在瀏覽器中查看分析結果 使用了jhat命令,就啟動了一個http服務,端口7000,通過在瀏覽器中輸入http://localhost:7000獲取分析結果 jhat在jdk9,10中已經被刪除,官方建議VisualVM代替
-stack false | true:關閉 | 打開對象分配調用棧跟蹤 -refs false | true : 關閉 | 打開對象引用跟蹤 -port port-number 設置jhat HTTP Server端口,默認7000 -exclude exclude-file:執行對象查詢時需要排除的數據成員 -baseline exclude-file:指定一個基準堆轉儲 -debug int:設置Debug級別 -version:啟動后顯示版本信息就退出 -J :傳入啟動參數,
jstack(JVM Stack Trace)
用于生成虛擬機指定進程當前時刻的線程快照,線程快照是當前虛擬機內指定進程的每一條線程正在執行的方法堆棧的集合 生成線程快照的作用:可用于定位線程出現長時間停頓的原因,如線程間死鎖、死循環,請求外部資源導致的長時間等待等問題,這些都是導致線程長時間停頓的常見原因,當線程出現停頓時,就可以用jstack顯示各個線程調用的堆棧情況 在thread dump中,要留意以下幾種狀態
死鎖,Deadlock 等待資源,Waiting on condition 等待獲取監視器,Waiting on monitor entry 阻塞,Blocked 執行中,Runnable 暫停,Suspended
package com. chapter12 ;
public class ThreadDeadLock { public static void main ( String [ ] args) { StringBuilder s1 = new StringBuilder ( ) ; StringBuilder s2 = new StringBuilder ( ) ; new Thread ( ) { @Override public void run ( ) { synchronized ( s1) { try { Thread . sleep ( 100 ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } synchronized ( s2) { s1. append ( "b" ) ; s2. append ( "2" ) ; System . out. println ( s1) ; System . out. println ( s2) ; } } } } . start ( ) ; new Thread ( ) { @Override public void run ( ) { synchronized ( s2) { try { Thread . sleep ( 100 ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } synchronized ( s1) { s1. append ( "d" ) ; s2. append ( "4" ) ; System . out. println ( s1) ; System . out. println ( s2) ; } } } } . start ( ) ; }
}
C : \Users \Administrator \IdeaProjects \jvm> jstack 12840
執行結果:
Found one Java - level deadlock:
== == == == == == == == == == == == == == =
"Thread-1" : waiting to lock monitor 0x0000000002d0b288 ( object 0x000000071649ee08 , a java. lang. StringBuilder) , which is held by "Thread-0"
"Thread-0" : waiting to lock monitor 0x0000000002d0c728 ( object 0x000000071649ee50 , a java. lang. StringBuilder) , which is held by "Thread-1" Java stack information for the threads listed above:
== == == == == == == == == == == == == == == == == == == == == == == == == =
"Thread-1" : at com. chapter12. ThreadDeadLock $2. run ( ThreadDeadLock . java: 40 ) - waiting to lock < 0x000000071649ee08> ( a java. lang. StringBuilder) - locked < 0x000000071649ee50> ( a java. lang. StringBuilder)
"Thread-0" : at com. chapter12. ThreadDeadLock $1. run ( ThreadDeadLock . java: 22 ) - waiting to lock < 0x000000071649ee50> ( a java. lang. StringBuilder) - locked < 0x000000071649ee08> ( a java. lang. StringBuilder) Found 1 deadlock.
public class ThreadSleepTest { public static void main ( String [ ] args) { System . out. println ( "hello - 1" ) ; try { Thread . sleep ( 1000 * 60 * 10 ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } System . out. println ( "hello - 2" ) ; }
}
>> jstack 920
"main" #1 prio= 5 os_prio= 0 tid= 0x00000000036d2800 nid= 0x1cb0 waiting on condition [ 0x000000000320f000 ] java. lang. Thread. State: TIMED_WAITING ( sleeping) at java. lang. Thread. sleep ( Native Method ) at com. chapter12. ThreadSleepTest. main ( ThreadSleepTest . java: 12 )
class Number implements Runnable { private int number = 1 ; @Override public void run ( ) { while ( true ) { synchronized ( this ) { if ( number <= 100 ) { try { Thread . sleep ( 500 ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } System . out. println ( Thread . currentThread ( ) . getName ( ) + ":" + number) ; number++ ; } else { break ; } } } }
}
public class ThreadSyncTest { public static void main ( String [ ] args) { Number number = new Number ( ) ; Thread t1 = new Thread ( number) ; Thread t2 = new Thread ( number) ; t1. setName ( "線程1" ) ; t2. setName ( "線程2" ) ; t1. start ( ) ; t2. start ( ) ; }
}
"線程2" #12 prio= 5 os_prio= 0 tid= 0x0000000027b56800 nid= 0x3380 waiting on condition [ 0x000000002879f000 ] java. lang. Thread. State: TIMED_WAITING ( sleeping) at java. lang. Thread. sleep ( Native Method ) at com. chapter12. Number. run ( ThreadSyncTest . java: 15 ) - locked < 0x00000007164a1960> ( a com. chapter12. Number) at java. lang. Thread. run ( Thread . java: 748 ) "線程1" #11 prio= 5 os_prio= 0 tid= 0x0000000027b4d800 nid= 0x1d18 waiting for monitor entry [ 0x000000002869f000 ] java. lang. Thread. State: BLOCKED ( on object monitor) at com. chapter12. Number. run ( ThreadSyncTest . java: 13 ) - waiting to lock < 0x00000007164a1960> ( a com. chapter12. Number) at java. lang. Thread. run ( Thread . java: 748 )
-F:當正常輸出的請求不被響應時,強制輸出線程堆棧 -l:除堆棧外,顯示關于鎖的附加信息 -m:如果調用到本地方法的話,可以顯示C/C++堆棧 -h:幫助操作
jcmd
基本情況
它是一個多功能工具,可以實現除了jstat之外所有命令的功能,用它來導出堆、內存使用、查看Java進程、導出線程信息、執行GC、JVM運行時間等
基本語法
-l:列出所有的JVM進程 pid help:針對指定的進程, pid 具體命令