在JDK的bin目錄下巍耗,可以看到很多工具秋麸,這些工具的程序體積都異常小巧【嫣基本都穩(wěn)定在17K左右灸蟆。這并非JDK開發(fā)團(tuán)隊刻意把他們制作得如此精煉,而是這些命令行工具大多數(shù)是JDK/lib/tools.jar類庫的一層薄包裝而已娄琉,它們主要的功能代碼是在tools類庫中實(shí)現(xiàn)的次乓。
之所以這樣做,是因?yàn)楫?dāng)應(yīng)用程序部署到生產(chǎn)環(huán)境后孽水,無論是直接接觸物理服務(wù)器還是遠(yuǎn)程Telnet到服務(wù)器上都可能會受到限制票腰。借助tools.jar類庫里面的接口,我們可以直接在應(yīng)用程序中實(shí)現(xiàn)功能強(qiáng)大的監(jiān)控分析功能女气。
下面列舉JDK主要命令行監(jiān)控工具的用途杏慰。
1.jps:虛擬機(jī)就進(jìn)程狀況工具
- JDK的很多小工具的名字都參考了UNIX命令的命名方式,jps名字像UNIX的ps命令之外炼鞠,也和ps命令類似:可以列出正在運(yùn)行的虛擬機(jī)進(jìn)程缘滥。并顯示虛擬機(jī)執(zhí)行主類(Main Class,main()函數(shù)所在的類)名稱以及這些進(jìn)程的本地虛擬機(jī)唯一ID(Local Virtual Machine Identifier,LVMID)。
- 雖然功能比較單一谒主,但它是使用頻率最高的JDK命令行工具朝扼,因?yàn)槠渌腏DK工具大多需要輸入它查詢到的LVMID來確定要監(jiān)控的是哪一個虛擬機(jī)進(jìn)程。對于本地虛擬機(jī)進(jìn)程來說霎肯,LVMID與操作系統(tǒng)的進(jìn)程ID是一致的擎颖。使用Windows的任務(wù)管理器或者UNIX的ps命令也可以
- 查詢到虛擬機(jī)進(jìn)程的LVMID榛斯,但如果同時啟動多個虛擬機(jī)進(jìn)程,無法根據(jù)進(jìn)程名稱定位時搂捧,那只有依賴jps命令顯示主類的功能才能區(qū)分了驮俗。
jps命令格式如下:
現(xiàn)在我們打開一個eclispe,寫一段程序允跑,例子如下:
package hjc.test9a;
import java.util.Scanner;
/**
* Created by cong on 2018/4/5.
*/
public class Main {
public Main() {
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
sc.next();
}
}
連續(xù)運(yùn)行2次王凑,打開cmd,再用jps查看,如下:
2.jstat:虛擬機(jī)統(tǒng)計信息監(jiān)控工具
jstat(JVM Statistics Monitoring Tool)是用于監(jiān)控虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具聋丝。它可以顯示本地或者遠(yuǎn)程虛擬機(jī)進(jìn)程中的類裝載索烹,內(nèi)存,垃圾收集潮针,JIT編譯等運(yùn)行數(shù)據(jù)术荤。
jstat命令格式為:
jstat [ option vmid [interval [s|ms] [count]] ]
對于命令格式中的VMID與LVMID需要特別說明一下:如果是本地虛擬機(jī)進(jìn)程,VMID與LVMID是一致的焦读,如果是遠(yuǎn)程虛擬機(jī)進(jìn)程子库,那VMID的格式應(yīng)當(dāng)是:
參數(shù)interval 和count代表查詢間隔和次數(shù),如果省略這兩個參數(shù)矗晃,說明只查詢一次仑嗅。假設(shè)要美250毫秒查詢一次進(jìn)程2764垃圾收集情況,一個查詢20次张症,那命令應(yīng)當(dāng)是:
jstat -gc 2764 250 20
選項(xiàng)option代表著用戶希望查詢的虛擬機(jī)信息仓技,主要分為3類:類裝載,垃圾收集俗他,運(yùn)行期編譯狀況脖捻,具體選項(xiàng)及作用請參考如下列表:
jstat 監(jiān)控選項(xiàng)眾多,這里僅舉一個例子演示如何查看監(jiān)控結(jié)果兆衅。繼續(xù)運(yùn)行上面的例子如下:
3.jinfo:Java配置信息工具
- jinfo(Configuration Info for Java) 的作用是實(shí)時地查看和調(diào)整虛擬機(jī)各項(xiàng)參數(shù)地沮。使用jps命令的-v參數(shù)可以查看虛擬機(jī)啟動時顯式指定的參數(shù)列表,但如果想知道未被顯式指定的參數(shù)的系統(tǒng)默認(rèn)值羡亩,除了去找資料摩疑,就只能使用jinfo的-flag選項(xiàng)進(jìn)行查詢了
- (如果只限于JDK1.6或以上版本的話,使用java -XX:+PrintFlagsFianl查看參數(shù)默認(rèn)值也是一個很好的選擇)畏铆,jinfo還可以使用-sysprops選項(xiàng)把虛擬機(jī)進(jìn)程的System.getProperties()的內(nèi)容打印出來雷袋。這個命令在JDK1.5時期已經(jīng)伴隨Linux的JDK發(fā)布,當(dāng)時只提供了信息查詢的功能辞居,
- JDK1.6之后片排,jinfo在Windows和Linux平臺都有提供寨腔,并且加入了運(yùn)行期修改參數(shù)的能力,可以使用-flag [+|-] name或者 -flag name=value 修改一部分運(yùn)行期可寫的虛擬機(jī)參數(shù)值率寡。JDK1.6中,jinfo對于Windows平臺功能仍然有很大的限制倚搬,只提供了最基本的-flag選項(xiàng)冶共。
jinfo的命令格式如下:
jinfo [option] pid
4.jmap:Java內(nèi)存映像工具
- jmap命令用于生成堆轉(zhuǎn)儲快照(一般稱為heapdump 或者dump文件),如果不是用jmap命令,想要獲取Java堆轉(zhuǎn)儲快照每界,要有一些暴力手段捅僵,
- 用-XX:HeapDumpOnOutOfMemoryError參數(shù),可以讓虛擬機(jī)在OOM異常出現(xiàn)之后自動生成dump文件眨层,
- 通過-XX:HeapDumpOnCtrlBreak參數(shù)則可以使用[Ctrl]+[Break]鍵讓虛擬機(jī)生成dump文件庙楚,又或者在Linux系統(tǒng)下通過Kill -3命令發(fā)送進(jìn)程退出信號嚇唬一下虛擬機(jī),也能拿到dump文件趴樱。
- jmap的作用并不僅僅是為了獲取dump文件馒闷,它還可以查詢finalize執(zhí)行隊列,java堆和永久代的詳細(xì)信息叁征,如空間使用率纳账,當(dāng)前用的是哪種收集器等。
jmap有不少功能在Windows平臺下都是受限制的捺疼,除了生成dump文件的-dump選項(xiàng)和用于查看每個類的實(shí)例疏虫,空間占用統(tǒng)計的-histo選項(xiàng)在所有操作系統(tǒng)都提供外,其余只能在Linux/Solaris下使用啤呼。
jmap命令格式:
jmap [option] vmid
option選項(xiàng)合法值與具體含義如下:
例子如下:
5.jhat:虛擬機(jī)堆轉(zhuǎn)儲快照分析工具
jhat命令與jmap搭配使用卧秘,來分析jmap生成的堆轉(zhuǎn)儲快照。jhat內(nèi)置了一個微型的HTTP/HTML服務(wù)器官扣,生成dump文件的分析結(jié)果后翅敌,可以在瀏覽器查看。實(shí)際工作中醇锚,如果沒有別的工具可用哼御,一般不會用jhat分析dump文件的。
原因有二:一是一般不會在部署應(yīng)用程序的服務(wù)器上直接分析dump文件焊唬,即使這樣做恋昼,也會盡量將dump文件復(fù)制到其他機(jī)器上進(jìn)行分析,因?yàn)榉治龉ぷ魇且粋€耗時并且消耗硬件資源的過程赶促。另外一個原因是jhat的分析功能相對于簡陋液肌,
后面會提到專業(yè)的工具VisualVM,以及專業(yè)分析dump的Eclispe Memory Analyzer鸥滨,等工具嗦哆。
6.jstack:Java堆棧跟蹤工具
- jstack命令用于生成虛擬機(jī)當(dāng)前時刻的線程快照(一般稱為threaddump或者javacore文件)谤祖。線程快照就是當(dāng)前虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧集合,生成線程快照的主要目的是定位線程出現(xiàn)長時間停頓的原因老速。
- 線程出現(xiàn)停頓的時候通過jstack來查看各個線程的調(diào)用堆棧粥喜,就可以知道沒有響應(yīng)的線程到底在后臺做些什么事情,或者等待著什么資源
jstack命令格式如下:
jstack [option] vmid
option選項(xiàng)的合法值與具體含義如下:
例子如下:
在JDK1.5中橘券,java.lang.Thread類新增了一個getAllStackTraces()方法用于獲取虛擬機(jī)中所有線程的StackTraceElement對象额湘。使用這個方法可以通過簡單的幾行代碼就完成了jstack的大部分功能。在實(shí)際項(xiàng)目中不妨調(diào)用這個方法做個管理員頁面旁舰,可以隨時使用瀏覽器
來查看線程堆棧锋华,例子如下:
package hjc.test9b;
import java.util.Map;
/**
* Created by cong on 2018/4/5.
*/
public class Main {
public static void main(String[] args) {
Map<Thread, StackTraceElement[]> m = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> en : m.entrySet()){
Thread t = en.getKey();
StackTraceElement[] v = en.getValue();
System.out.println("The Thread name is :" + t.getName());
for (StackTraceElement s : v){
System.err.println("\t" + s.toString());
}
}
}
}
運(yùn)行結(jié)果如下:
7.JConsole:Java監(jiān)控與管理控制平臺。
JConsole是一種基于JMX的可視化監(jiān)視箭窜,管理工具毯焕。通過JDK/bin目錄下的jconsole.exe來啟動JConsole
雙機(jī)進(jìn)去,可以看到主界面包括概述磺樱,內(nèi)存纳猫,線程,類坊罢,VM摘要续担,MBean6個頁面
對線程的監(jiān)控例子如下:
死循環(huán)演示:
/**
* 線程死循環(huán)演示
*/
public static void createBusyThread() {
Thread thread = new Thread(new Runnable() {
public void run() {
while (true)
;
}
}, "testBusyThread");
thread.start();
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
createBusyThread();
}
線程鎖等待演示:
/**
* 線程鎖等待演示
*/
public static void createLockThread(final Object lock) {
Thread thread = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
try {
lock.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "testLockThread");
thread.start();
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
Object obj = new Object();
createLockThread(obj);
}
死鎖代碼樣例:
public class SynAddRunable implements Runnable {
int a, b;
public SynAddRunable(int a, int b) {
this.a = a;
this.b = b;
}
public void run() {
synchronized (Integer.valueOf(a)) {
synchronized (Integer.valueOf(b)) {
System.out.println(a + b);
}
}
}
public static void main(String[] args) {
for ( int i = 0; i < 100; i++) {
new Thread(new SynAddRunable(1, 2)).start();
new Thread(new SynAddRunable(2, 1)).start();
}
}
}
這段代碼開了200個線程去分別計算1+2以及2+1的值,造成死鎖的原因是Integer.valueOf()方法基于減少對象創(chuàng)建次數(shù)和節(jié)省內(nèi)存的考慮活孩,[-128,127]之間的數(shù)字會被緩存物遇,當(dāng)valueOf()方法傳入?yún)?shù)在這個范圍之內(nèi),將直接返回緩存中的對象憾儒。也就是說
代碼中調(diào)用200次Integer.valueOf()方法一共就返回了兩個不同的對象询兴。假如在某個線程的兩個synchronized塊之間發(fā)生了一次線程切換,那就會出現(xiàn)線程A等線程B持有的Integer.valueOf(1),線程B又等待著被線程A持有的Integer.valueOf(2),結(jié)果大家都跑不下去起趾。
出現(xiàn)死鎖后诗舰,點(diǎn)擊Jconsole線程面板的檢測到死鎖的按鈕,將出現(xiàn)一個新的死鎖標(biāo)簽训裆。如下圖:
8.VisualVM:多合一故障處理工具
VisualVM可以做到:
1.顯示虛擬機(jī)繼承以及進(jìn)程的配置眶根,環(huán)境信息(jps,jinfo)
2.監(jiān)視應(yīng)用程序的CPU,GC,堆,方法區(qū)边琉,以及線程信息(jstack,jstat)
3.dump以及分析堆轉(zhuǎn)快照(jmap属百,jhat)
4.方法級的程序運(yùn)行性能分析,找出被調(diào)用最多变姨,運(yùn)行時間最長的方法族扰。
5.離線程序快照:收集程序的運(yùn)行時配置,線程dump,內(nèi)存dump等信息建立一個快照渔呵,可以將快照發(fā)送開發(fā)者進(jìn)行BUG反饋怒竿。
安裝后,打開如下:
轉(zhuǎn)載自:
https://www.cnblogs.com/huangjuncong/p/8995333.html
Btrace參考:
基于Btrace的監(jiān)控調(diào)試
https://blog.51cto.com/zero01/2143096