強(qiáng)大的JVM監(jiān)控工具!
介紹
在生產(chǎn)環(huán)境中,經(jīng)常會(huì)遇到各種各樣奇葩的性能問(wèn)題,所以掌握最基本的JVM命令行監(jiān)控工具還是很有必要的
名稱(chēng) | 主要作用 |
---|---|
jps | 查看正在運(yùn)行的Java進(jìn)程 |
jstack | 打印線程快照 |
jmap | 導(dǎo)出堆內(nèi)存映像文件 |
jstat | 查看jvm統(tǒng)計(jì)信息 |
jinfo | 實(shí)時(shí)查看和修改jvm配置參數(shù) |
jhat | 用于分析heapdump文件 |
jps:查看正在運(yùn)行的Java進(jìn)程
jps可以列出正在運(yùn)行的Java進(jìn)程,并顯示虛擬機(jī)執(zhí)行主類(lèi)(Main Class,main()函數(shù)所在的類(lèi))名稱(chēng)以及進(jìn)程id
「如果想看一個(gè)命令的后面加 -help參數(shù)即可」
- [root@VM-0-14-centos ~]# jps -help
- usage: jps [-help]
- jps [-q] [-mlvV] [<hostid>]
- Definitions:
- <hostid>: <hostname>[:<port>]
「可以看到可以監(jiān)控遠(yuǎn)程服務(wù),但是基于安全考慮,一般不使用」
常見(jiàn)的選項(xiàng)如下
選項(xiàng) | 作用 |
---|---|
-q | 只輸出進(jìn)程id |
-m | 輸出傳遞給主類(lèi)main函數(shù)的參數(shù) |
-l | 輸出主類(lèi)全類(lèi)名,如果進(jìn)程執(zhí)行的是Jar包,輸出jar包名字 |
-v | 程序啟動(dòng)時(shí)指定的jvm參數(shù) |
- cis@mt002:~$ jps
- 70208 KmpService
- 183525 LinkAnalysisServer
- 25160 MipSerachServer
- cis@mt002:~$ jps -l
- 70208 com.st.kmp.main.KmpService
- 183525 com.st.cis.main.LinkAnalysisServer
- 25160 com.st.cis.main.MipSerachServer
jstack:打印線程快照
「查看某個(gè)Java進(jìn)程中所有線程的狀態(tài)。一般用來(lái)定位線程出現(xiàn)長(zhǎng)時(shí)間停頓的原因,如發(fā)生死循環(huán),死鎖,請(qǐng)求外部資源長(zhǎng)時(shí)間等待等!」
- public class DeadLockDemo {
- private static Object lockA = new Object();
- private static Object lockB = new Object();
- public static void main(String[] args) {
- Thread threadA = new Thread(() -> {
- synchronized (lockA) {
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("get lockA");
- synchronized (lockB) {
- System.out.println("threadA run finish");
- }
- }
- });
- Thread threadB = new Thread(() -> {
- synchronized (lockB) {
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("get lockB");
- synchronized (lockA) {
- System.out.println("threadB run finish");
- }
- }
- });
- threadA.setName("myThreadA");
- threadB.setName("myThreadB");
- threadA.start();
- threadB.start();
- }
- }
「我寫(xiě)了一個(gè)死鎖的例子,啟動(dòng)后執(zhí)行jps找到進(jìn)程id為19457」
- peng@pengdeMacBook-Pro ~ % jps
- 19457 DeadLockDemo
- 19458 Launcher
- 2658
- 19459 Jps
接著執(zhí)行如下命令,列出了這個(gè)進(jìn)程每個(gè)線程的執(zhí)行狀態(tài)
- jstack 19457
「從圖中可以看到有很多線程,GC線程,myThreadA,myThreadB等,其中myThreadA和myThreadB的線程狀態(tài)為BLOCKED,并且在最后提示出了死鎖發(fā)生的位置」
jmap:導(dǎo)出堆內(nèi)存映像文件
「jmap主要用來(lái)用來(lái)導(dǎo)出堆內(nèi)存映像文件,看是否發(fā)生內(nèi)存泄露等?!?/p>
生產(chǎn)環(huán)境我們一般會(huì)配置如下參數(shù),讓虛擬機(jī)在OOM異常出現(xiàn)之后自動(dòng)生成dump文件
- -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/peng
執(zhí)行如下命令即可手動(dòng)獲得dump文件
- jmap -dump:file=文件名.dump 進(jìn)程id
「分析堆內(nèi)存的工具有很多,如Java VisualVM,jhat等。但個(gè)人覺(jué)得最好用的就是Eclipse Memory Analyzer,沒(méi)有之一」
jstat:查看jvm統(tǒng)計(jì)信息
「jstat可以顯示本地或者遠(yuǎn)程虛擬機(jī)進(jìn)程中的類(lèi)裝載、 內(nèi)存、 垃圾收集、 JIT編譯等運(yùn)行數(shù)據(jù)」
用jstat查看一下類(lèi)裝載的信息。我個(gè)人很少使用這個(gè)命令,命令行看垃圾收集信息真不如看圖形界面方便,就不多做介紹了。
- [root@VM-0-14-centos ~]# jstat -class 19402
- Loaded Bytes Unloaded Bytes Time
- 10229 19679.1 52 76.0 5.33
含義如下
Loaded | 解釋 |
---|---|
Loaded | 加載類(lèi)的個(gè)數(shù) |
Bytes | 加載類(lèi)的字節(jié)數(shù) |
Unloaded | 卸載類(lèi)的個(gè)數(shù) |
Bytes | 卸載類(lèi)的字節(jié)數(shù) |
Time | 花費(fèi)的時(shí)間 |
jinfo:實(shí)時(shí)查看和修改jvm配置參數(shù)
jinfo的作用是實(shí)時(shí)地查看和修改虛擬機(jī)各項(xiàng)參數(shù)。
「使用jps命令的-v參數(shù)可以查看虛擬機(jī)啟動(dòng)時(shí)顯式指定的參數(shù)列表」,但如果想知道未被顯式指定的參數(shù)的系統(tǒng)默認(rèn)值,除了去找資料外,就只能使用jinfo的-flag選項(xiàng)進(jìn)行查詢(xún)了(如果只限于JDK 1.6或以上版本的話(huà),使用java -XX:+PrintFlagsFinal查看參數(shù)默認(rèn)值也是一個(gè)很好的選擇)
「jinfo flags pid在高版本才能正常使用,我在jdk1.8這個(gè)版本不能正常使用」
應(yīng)用程序設(shè)置如下參數(shù)
- -Xmx10m -Xms10m
查看最大堆內(nèi)存和是否打印GC日志,可以看到不打印GC日志 接著設(shè)置打印GC日志,再次查看,打印GC日志
- peng@pengdeMacBook-Pro ~ % jinfo -flag MaxHeapSize 20253
- -XX:MaxHeapSize=10485760
- peng@pengdeMacBook-Pro ~ % jinfo -flag PrintGCDetails 20253
- -XX:-PrintGCDetails
- peng@pengdeMacBook-Pro ~ % jinfo -flag +PrintGCDetails 20253
- peng@pengdeMacBook-Pro ~ % jinfo -flag PrintGCDetails 20253
- -XX:+PrintGCDetails
「Xmx是MaxHeapSize的別名」
本文轉(zhuǎn)載自微信公眾號(hào)「Java識(shí)堂」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java識(shí)堂公眾號(hào)。