這些命令在 JDK 安裝目錄下的 bin 目錄下:html
jps
(JVM Process Status): 相似 UNIX 的 ps
命令。用戶查看全部 Java 進程的啓動類、傳入參數和 Java 虛擬機參數等信息;jstat
( JVM Statistics Monitoring Tool): 用於收集 HotSpot 虛擬機各方面的運行數據;jinfo
(Configuration Info for Java) : Configuration Info forJava,顯示虛擬機配置信息;jmap
(Memory Map for Java) :生成堆轉儲快照;jhat
(JVM Heap Dump Browser ) : 用於分析 heapdump 文件,它會創建一個 HTTP/HTML 服務器,讓用戶能夠在瀏覽器上查看分析結果;jstack
(Stack Trace for Java):生成虛擬機當前時刻的線程快照,線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合。jps
:查看全部 Java 進程jps
(JVM Process Status) 命令相似 UNIX 的 ps
命令。java
jps
:顯示虛擬機執行主類名稱以及這些進程的本地虛擬機惟一 ID(Local Virtual Machine Identifier,LVMID)。jps -q
:只輸出進程的本地虛擬機惟一 ID。git
C:\Users\SnailClimb>jps 7360 NettyClient2 17396 7972 Launcher 16504 Jps 17340 NettyServer
jps -l
:輸出主類的全名,若是進程執行的是 Jar 包,輸出 Jar 路徑。github
C:\Users\SnailClimb>jps -l 7360 firstNettyDemo.NettyClient2 17396 7972 org.jetbrains.jps.cmdline.Launcher 16492 sun.tools.jps.Jps 17340 firstNettyDemo.NettyServer
jps -v
:輸出虛擬機進程啓動時 JVM 參數。瀏覽器
jps -m
:輸出傳遞給 Java 進程 main() 函數的參數。服務器
jstat
: 監視虛擬機各類運行狀態信息jstat(JVM Statistics Monitoring Tool) 使用於監視虛擬機各類運行狀態信息的命令行工具。 它能夠顯示本地或者遠程(須要遠程主機提供 RMI 支持)虛擬機進程中的類信息、內存、垃圾收集、JIT 編譯等運行數據,在沒有 GUI,只提供了純文本控制檯環境的服務器上,它將是運行期間定位虛擬機性能問題的首選工具。jvm
jstat
命令使用格式:ide
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
好比 jstat -gc -h3 31736 1000 10
表示分析進程 id 爲 31736 的 gc 狀況,每隔 1000ms 打印一次記錄,打印 10 次中止,每 3 行後打印指標頭部。函數
常見的 option 以下:工具
jstat -class vmid
:顯示 ClassLoader 的相關信息;jstat -compiler vmid
:顯示 JIT 編譯的相關信息;jstat -gc vmid
:顯示與 GC 相關的堆信息;jstat -gccapacity vmid
:顯示各個代的容量及使用狀況;jstat -gcnew vmid
:顯示新生代信息;jstat -gcnewcapcacity vmid
:顯示新生代大小與使用狀況;jstat -gcold vmid
:顯示老年代和永久代的信息;jstat -gcoldcapacity vmid
:顯示老年代的大小;jstat -gcpermcapacity vmid
:顯示永久代大小;jstat -gcutil vmid
:顯示垃圾收集信息;另外,加上 -t
參數能夠在輸出信息上加一個 Timestamp 列,顯示程序的運行時間。
jinfo
: 實時地查看和調整虛擬機各項參數jinfo vmid
:輸出當前 jvm 進程的所有參數和系統屬性 (第一部分是系統的屬性,第二部分是 JVM 的參數)。
jinfo -flag name vmid
:輸出對應名稱的參數的具體值。好比輸出 MaxHeapSize、查看當前 jvm 進程是否開啓打印 GC 日誌 ( -XX:PrintGCDetails
:詳細 GC 日誌模式,這兩個都是默認關閉的)。
C:\Users\SnailClimb>jinfo -flag MaxHeapSize 17340 -XX:MaxHeapSize=2124414976 C:\Users\SnailClimb>jinfo -flag PrintGC 17340 -XX:-PrintGC
使用 jinfo 能夠在不重啓虛擬機的狀況下,能夠動態的修改 jvm 的參數。尤爲在線上的環境特別有用,請看下面的例子:
jinfo -flag [+|-]name vmid
開啓或者關閉對應名稱的參數。
C:\Users\SnailClimb>jinfo -flag PrintGC 17340 -XX:-PrintGC C:\Users\SnailClimb>jinfo -flag +PrintGC 17340 C:\Users\SnailClimb>jinfo -flag PrintGC 17340 -XX:+PrintGC
jmap
:生成堆轉儲快照jmap
(Memory Map for Java)命令用於生成堆轉儲快照。 若是不使用 jmap
命令,要想獲取 Java 堆轉儲,可使用 「-XX:+HeapDumpOnOutOfMemoryError」
參數,可讓虛擬機在 OOM 異常出現以後自動生成 dump 文件,Linux 命令下能夠經過 kill -3
發送進程退出信號也能拿到 dump 文件。
jmap
的做用並不只僅是爲了獲取 dump 文件,它還能夠查詢 finalizer 執行隊列、Java 堆和永久代的詳細信息,如空間使用率、當前使用的是哪一種收集器等。和jinfo
同樣,jmap
有很多功能在 Windows 平臺下也是受限制的。
示例:將指定應用程序的堆快照輸出到桌面。後面,能夠經過 jhat、Visual VM 等工具分析該堆文件。
C:\Users\SnailClimb>jmap -dump:format=b,file=C:\Users\SnailClimb\Desktop\heap.hprof 17340 Dumping heap to C:\Users\SnailClimb\Desktop\heap.hprof ... Heap dump file created
jhat
: 分析 heapdump 文件jhat
用於分析 heapdump 文件,它會創建一個 HTTP/HTML 服務器,讓用戶能夠在瀏覽器上查看分析結果。
C:\Users\SnailClimb>jhat C:\Users\SnailClimb\Desktop\heap.hprof Reading from C:\Users\SnailClimb\Desktop\heap.hprof... Dump file created Sat May 04 12:30:31 CST 2019 Snapshot read, resolving... Resolving 131419 objects... Chasing references, expect 26 dots.......................... Eliminating duplicate references.......................... Snapshot resolved. Started HTTP server on port 7000 Server is ready.
jstack
:生成虛擬機當前時刻的線程快照jstack
(Stack Trace for Java)命令用於生成虛擬機當前時刻的線程快照。線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合.
生成線程快照的目的主要是定位線程長時間出現停頓的緣由,如線程間死鎖、死循環、請求外部資源致使的長時間等待等都是致使線程長時間停頓的緣由。線程出現停頓的時候經過jstack
來查看各個線程的調用堆棧,就能夠知道沒有響應的線程到底在後臺作些什麼事情,或者在等待些什麼資源。
下面是一個線程死鎖的代碼。咱們下面會經過 jstack
命令進行死鎖檢查,輸出死鎖信息,找到發生死鎖的線程。
public class DeadLockDemo { private static Object resource1 = new Object();//資源 1 private static Object resource2 = new Object();//資源 2 public static void main(String[] args) { new Thread(() -> { synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource2"); synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); } } }, "線程 1").start(); new Thread(() -> { synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource1"); synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); } } }, "線程 2").start(); } }
Output
Thread[線程 1,5,main]get resource1
Thread[線程 2,5,main]get resource2 Thread[線程 1,5,main]waiting get resource2 Thread[線程 2,5,main]waiting get resource1
線程 A 經過 synchronized (resource1) 得到 resource1 的監視器鎖,而後經過 Thread.sleep(1000);
讓線程 A 休眠 1s 爲的是讓線程 B 獲得執行而後獲取到 resource2 的監視器鎖。線程 A 和線程 B 休眠結束了都開始企圖請求獲取對方的資源,而後這兩個線程就會陷入互相等待的狀態,這也就產生了死鎖。
經過 jstack
命令分析:
C:\Users\SnailClimb>jps 13792 KotlinCompileDaemon 7360 NettyClient2 17396 7972 Launcher 8932 Launcher 9256 DeadLockDemo 10764 Jps 17340 NettyServer C:\Users\SnailClimb>jstack 9256
輸出的部份內容以下:
Found one Java-level deadlock: ============================= "線程 2": waiting to lock monitor 0x000000000333e668 (object 0x00000000d5efe1c0, a java.lang.Object), which is held by "線程 1" "線程 1": waiting to lock monitor 0x000000000333be88 (object 0x00000000d5efe1d0, a java.lang.Object), which is held by "線程 2" Java stack information for the threads listed above: =================================================== "線程 2": at DeadLockDemo.lambda$main$1(DeadLockDemo.java:31) - waiting to lock <0x00000000d5efe1c0> (a java.lang.Object) - locked <0x00000000d5efe1d0> (a java.lang.Object) at DeadLockDemo$$Lambda$2/1078694789.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "線程 1": at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16) - waiting to lock <0x00000000d5efe1d0> (a java.lang.Object) - locked <0x00000000d5efe1c0> (a java.lang.Object) at DeadLockDemo$$Lambda$1/1324119927.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock.
能夠看到 jstack
命令已經幫咱們找到發生死鎖的線程的具體信息。
JConsole 是基於 JMX 的可視化監視、管理工具。能夠很方便的監視本地及遠程服務器的 java 進程的內存使用狀況。你能夠在控制檯輸出console
命令啓動或者在 JDK 目錄下的 bin 目錄找到jconsole.exe
而後雙擊啓動。
若是須要使用 JConsole 鏈接遠程進程,能夠在遠程 Java 程序啓動時加上下面這些參數:
-Djava.rmi.server.hostname=外網訪問 ip 地址 -Dcom.sun.management.jmxremote.port=60001 //監控的端口號 -Dcom.sun.management.jmxremote.authenticate=false //關閉認證 -Dcom.sun.management.jmxremote.ssl=false
在使用 JConsole 鏈接時,遠程進程地址以下:
外網訪問 ip 地址:60001
JConsole 能夠顯示當前內存的詳細信息。不只包括堆內存/非堆內存的總體信息,還能夠細化到 eden 區、survivor 區等的使用狀況,以下圖所示。
點擊右邊的「執行 GC(G)」按鈕能夠強制應用程序執行一個 Full GC。
- 新生代 GC(Minor GC):指發生新生代的的垃圾收集動做,Minor GC 很是頻繁,回收速度通常也比較快。
- 老年代 GC(Major GC/Full GC):指發生在老年代的 GC,出現了 Major GC 常常會伴隨至少一次的 Minor GC(並不是絕對),Major GC 的速度通常會比 Minor GC 的慢 10 倍以上。
相似咱們前面講的 jstack
命令,不過這個是可視化的。
最下面有一個"檢測死鎖 (D)"按鈕,點擊這個按鈕能夠自動爲你找到發生死鎖的線程以及它們的詳細信息 。
VisualVM 提供在 Java 虛擬機 (Java Virutal Machine, JVM) 上運行的 Java 應用程序的詳細信息。在 VisualVM 的圖形用戶界面中,您能夠方便、快捷地查看多個 Java 應用程序的相關信息。Visual VM 官網:https://visualvm.github.io/ 。Visual VM 中文文檔:https://visualvm.github.io/documentation.html。
下面這段話摘自《深刻理解 Java 虛擬機》。
VisualVM(All-in-One Java Troubleshooting Tool)是到目前爲止隨 JDK 發佈的功能最強大的運行監視和故障處理程序,官方在 VisualVM 的軟件說明中寫上了「All-in-One」的描述字樣,預示着他除了運行監視、故障處理外,還提供了不少其餘方面的功能,如性能分析(Profiling)。VisualVM 的性能分析功能甚至比起 JProfiler、YourKit 等專業且收費的 Profiling 工具都不會遜色多少,並且 VisualVM 還有一個很大的優勢:不須要被監視的程序基於特殊 Agent 運行,所以他對應用程序的實際性能的影響很小,使得他能夠直接應用在生產環境中。這個優勢是 JProfiler、YourKit 等工具沒法與之媲美的。
VisualVM 基於 NetBeans 平臺開發,所以他一開始就具有了插件擴展功能的特性,經過插件擴展支持,VisualVM 能夠作到:
這裏就不具體介紹 VisualVM 的使用,若是想了解的話能夠看: