Java經常使用命令:jps、jstack、jmap、jstat(帶有實例教程)

 

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/u013310517/article/details/80990924

 

 

查看Java進程:jps

用法介紹 
這裏寫圖片描述 
jps命令:顯示全部進程號和短的類名稱 
這裏寫圖片描述 
Jps –q 命令:只顯示進程號 
這裏寫圖片描述 
Jps –l 用於傳輸主函數的完整路徑 
這裏寫圖片描述 
Jps –v 顯示傳遞給Java虛擬機的參數(感受這個命令纔是完美,把虛擬機的一些參數全都打印出來) 
這裏寫圖片描述html

查看線程堆棧命令:jstack命令

Jstack命令主要用來查看Java線程的調用堆棧的,能夠用來分析線程問題(如死鎖)。談到線程,在Java裏面,線程一共有6中狀態java

  • New 新建 ————- 不會出如今dump中
  • Runnable 正在運行中——–在虛擬機內執行
  • Blocked 阻塞————受阻塞,並等待監視器鎖
  • Waiting 等待————無限期等待另外一個線程執行特定操做
  • Timed_waiting 超時等待————有時限等待另外一個線程的操做
  • Terminated 終止/結束————已退出的

Monitor 
在多線程的 JAVA程序中,實現線程之間的同步,就要說說 Monitor。 Monitor是 Java中用以實現線程之間的互斥與協做的主要手段,它能夠當作是對象或者 Class的鎖。每個對象都有,也僅有一個 monitor。下 面這個圖,描述了線程和 Monitor之間關係,以 及線程的狀態轉換圖: 
這裏寫圖片描述c++

進入區(Entrt Set):算法

表示線程經過synchronized要求獲取對象的鎖。若是對象未被鎖住,則迚入擁有者;不然則在進入區等待。一旦對象鎖被其餘線程釋放,當即參與競爭。服務器

擁有者(The Owner):markdown

表示某一線程成功競爭到對象鎖。網絡

等待區(Wait Set):多線程

表示線程經過對象的wait方法,釋放對象的鎖,並在等待區等待被喚醒。oracle

從圖中能夠看出,一個 Monitor在某個時刻,只能被一個線程擁有,該線程就是 「Active Thread」,而其它線程都是 「Waiting Thread」,分別在兩個隊列 「 Entry Set」和 「Wait Set」裏面等候。在 「Entry Set」中等待的線程狀態是 「Waiting for monitor entry」,而在 「Wait Set」中等待的線程狀態是 「in Object.wait()」。 先看 「Entry Set」裏面的線程。咱們稱被 synchronized保護起來的代碼段爲臨界區。當一個線程申請進入臨界區時,它就進入了 「Entry Set」隊列。對應的 code就像:框架

synchronized(obj) {
......... }
  • 1
  • 2
  • 3
  • 4

調用修飾 
表示線程在方法調用時,額外的重要的操做。線程Dump分析的重要信息。修飾上方的方法調用。 
locked <地址> 目標:使用synchronized申請對象鎖成功,監視器的擁有者。 
waiting to lock <地址> 目標:使用synchronized申請對象鎖未成功,在迚入區等待。 
waiting on <地址> 目標:使用synchronized申請對象鎖成功後,釋放鎖幵在等待區等待。 
parking to wait for <地址> 目標

locked

at oracle.jdbc.driver.PhysicalConnection.prepareStatement - locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection) at oracle.jdbc.driver.PhysicalConnection.prepareStatement - locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection) at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

經過synchronized關鍵字,成功獲取到了對象的鎖,成爲監視器的擁有者,在臨界區內操做。對象鎖是能夠線程重入的。

waiting to lock

at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165) - waiting to lock <0x0000000097ba9aa8> (a CacheHolder) at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder at com.jiuqi.dna.core.impl.ContextImpl.find at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo
  • 1
  • 2
  • 3
  • 4
  • 5

經過synchronized關鍵字,沒有獲取到了對象的鎖,線程在監視器的進入區等待。在調用棧頂出現,線程狀態爲Blocked。

waiting on

at java.lang.Object.wait(Native Method) - waiting on <0x00000000da2defb0> (a WorkingThread) at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo - locked <0x00000000da2defb0> (a WorkingThread) at com.jiuqi.dna.core.impl.WorkingThread.run 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

經過synchronized關鍵字,成功獲取到了對象的鎖後,調用了wait方法,進入對象的等待區等待。在調用棧頂出現,線程狀態爲WAITING或TIMED_WATING。

parking to wait for 
park是基本的線程阻塞原語,不經過監視器在對象上阻塞。隨concurrent包會出現的新的機制,不synchronized體系不一樣。

線程動做 
線程狀態產生的緣由 
runnable:狀態通常爲RUNNABLE。 
in Object.wait():等待區等待,狀態爲WAITING或TIMED_WAITING。 
waiting for monitor entry:進入區等待,狀態爲BLOCKED。 
waiting on condition:等待區等待、被park。 
sleeping:休眠的線程,調用了Thread.sleep()。

Wait on condition 該狀態出如今線程等待某個條件的發生。具體是什麼緣由,能夠結合 stacktrace來分析。 最多見的狀況就是線程處於sleep狀態,等待被喚醒。 常見的狀況還有等待網絡IO:在java引入nio以前,對於每一個網絡鏈接,都有一個對應的線程來處理網絡的讀寫操做,即便沒有可讀寫的數據,線程仍然阻塞在讀寫操做上,這樣有可能形成資源浪費,並且給操做系統的線程調度也帶來壓力。在 NewIO裏採用了新的機制,編寫的服務器程序的性能和可擴展性都獲得提升。 正等待網絡讀寫,這多是一個網絡瓶頸的徵兆。由於網絡阻塞致使線程沒法執行。一種狀況是網絡很是忙,幾 乎消耗了全部的帶寬,仍然有大量數據等待網絡讀 寫;另外一種狀況也多是網絡空閒,但因爲路由等問題,致使包沒法正常的到達。因此要結合系統的一些性能觀察工具來綜合分析,好比 netstat統計單位時間的發送包的數目,若是很明顯超過了所在網絡帶寬的限制 ; 觀察 cpu的利用率,若是系統態的 CPU時間,相對於用戶態的 CPU時間比例較高;若是程序運行在 Solaris 10平臺上,能夠用 dtrace工具看系統調用的狀況,若是觀察到 read/write的系統調用的次數或者運行時間遙遙領先;這些都指向因爲網絡帶寬所限致使的網絡瓶頸。(來自http://www.blogjava.net/jzone/articles/303979.html

jstack 命令詳解 
這裏寫圖片描述 
簡單介紹:

F當’jstack [-l] pid’沒有相應的時候強制打印棧信息 -l長列表. 打印關於鎖的附加信息,例如屬於java.util.concurrent的ownable synchronizers列表. -m打印java和native c/c++框架的全部棧信息. -h | -help打印幫助信息 pid 須要被打印配置信息的java進程id,能夠用jps查詢.

第一個實戰代碼:

/** * Created by Cser_W on 2018/7/10. */ public class JstackDemo { public static void main(String[] args){ while (true) { //do nothing } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

先利用 jps 查看進程號 
這裏寫圖片描述 
利用jstack 進程號查看線程堆棧信息,若是發現本身寫的代碼一直處於Runnable狀態,這有很大多是本身寫了個死循環。 
第二個實戰代碼

/** * Created by Cser_W on 2018/7/10. */ public class JstackDemo1 { public static void main(String[] args){ Thread thread = new Thread(new Thread1()); thread.start(); } } class Thread1 extends Thread { @Override public void run(){ while (true) { System.out.println(1); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這裏寫圖片描述
咱們能看到: 
線程的狀態: WAITING 線程的調用棧 線程的當前鎖住的資源: < < <0x00000000da380ee0>>> 線程當前等待的資源:< < <0x00000000da380ee0>>>

爲何同時鎖住的等待同一個資源: 
線程的執行中,先得到了這個對象的 Monitor(對應於 locked < <0x00000000da380ee0>>)。當執行到 obj.wait(), 線程即放棄了 Monitor的全部權,進入 「wait set」隊列(對應於 waiting on < <0x00000000da380ee0>> )。

死鎖模擬實戰

package com.wxy.test; /** * Created by Cser_W on 2018/7/10. */ public class JstackDemo2 { public static void main(String[] args){ Thread thread1 = new Thread(new DeadLockClass(true)); Thread thread2 = new Thread((new DeadLockClass(false))); thread1.start(); thread2.start(); } } class DeadLockClass implements Runnable { public boolean flag; DeadLockClass(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { while (true) { synchronized (Suo.o1) { System.out.println("o1" + Thread.currentThread().getName()); synchronized (Suo.o2) { System.out.println("o2" + Thread.currentThread().getName()); } } } } else { while (true) { synchronized (Suo.o2) { System.out.println("o2" + Thread.currentThread().getName()); synchronized (Suo.o1) { System.out.println("o1" + Thread.currentThread().getName()); } } } } } } class Suo { static Object o1 = new Object(); static Object o2 = new Object(); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

運行輸出: 
這裏寫圖片描述 
上圖已經鎖死,只要兩個線程都啓動起來,一定會發生死鎖。這個時候趕忙拿jstack練手了 
用jstack命令顯示: 
這裏寫圖片描述

打印內存映射,製做堆Dump命令:Jmap

堆map的概述

堆Dump是反應Java堆使用狀況的內存鏡像,其中主要包括系統信息、虛擬機屬性、完整的線程Dump、全部類和對象的狀態等。 通常,在內存不足、GC異常等狀況下,咱們就會懷疑有內存泄露。這個時候咱們就能夠製做堆Dump來查看具體狀況

用法摘要

Usage:
    jmap [option] <pid>
        (to connect to running process) jmap [option] <executable <core> (to connect to a core file) jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server) where <option> is one of: <none> to print same info as Solaris pmap -heap to print java heap summary -histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects -permstat to print permanent generation statistics -finalizerinfo to print information on objects awaiting finalization -dump:<dump-options> to dump java heap in hprof binary format dump-options: live dump only live objects; if not specified, all objects in the heap are dumped. format=b binary format file=<file> dump heap to <file> Example: jmap -dump:live,format=b,file=heap.bin <pid> -F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode. -h | -help to print this help message -J<flag> to pass <flag> directly to the runtime system 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

指定進程號(pid)的進程 jmap [ option ] 指定核心文件 jmap [ option ] 指定遠程調試服務器jmap [ option ] [server-id@] 
參數: 
option 選項參數是互斥的(不可同時使用)。想要使用選項參數,直接跟在命令名稱後便可。 
pid 須要打印配置信息的進程ID。該進程必須是一個Java進程。想要獲取運行的Java進程列表,你可使用jps。 
executable 產生核心dump的Java可執行文件。 
core 須要打印配置信息的核心文件。 
remote-hostname-or-IP 遠程調試服務器的(請查看jsadebugd)主機名或IP地址。 
server-id 可選的惟一id,若是相同的遠程主機上運行了多臺調試服務器,用此選項參數標識服務器。 
選項: 
若是使用不帶選項參數的jmap打印共享對象映射,將會打印目標虛擬機中加載的每一個共享對象的起始地址、映射大小以及共享對象文件的路徑全稱。這與Solaris的pmap工具比較類似。 
-dump:[live,]format=b,file= 以hprof二進制格式轉儲Java堆到指定filename的文件中。live子選項是可選的。若是指定了live子選項,堆中只有活動的對象會被轉儲。想要瀏覽heap dump,你可使用jhat(Java堆分析工具)讀取生成的文件。 
-finalizerinfo 打印等待終結的對象信息。 
-heap 打印一個堆的摘要信息,包括使用的GC算法、堆配置信息和generation wise heap usage。 
-histo[:live] 打印堆的柱狀圖。其中包括每一個Java類、對象數量、內存大小(單位:字節)、徹底限定的類名。打印的虛擬機內部的類名稱將會帶有一個’*’前綴。若是指定了live子選項,則只計算活動的對象。 
-permstat 打印Java堆內存的永久保存區域的類加載器的智能統計信息。對於每一個類加載器而言,它的名稱、活躍度、地址、父類加載器、它所加載的類的數量和大小都會被打印。此外,包含的字符串數量和大小也會被打印。 
-F 強制模式。若是指定的pid沒有響應,請使用jmap -dump或jmap -histo選項。此模式下,不支持live子選項。 
-h 打印幫助信息。 
-help 打印幫助信息。 
-J 指定傳遞給運行jmap的JVM的參數。

查看java 堆(heap)使用狀況,執行命令:

Jmap –heap pid 
這裏寫圖片描述

查看堆內存(histogram)中的對象數量及大小。執行命令:

Jmap –histo pid 
這裏寫圖片描述

總結: 
1. 若是程序內存不足或者頻繁GC,頗有可能存在內存泄露狀況,這時候就要藉助Java堆Dump查看對象的狀況。 
2.要製做堆Dump能夠直接使用jvm自帶的jmap命令 
3.能夠先使用jmap -heap命令查看堆的使用狀況,看一下各個堆空間的佔用狀況。 
4.使用jmap -histo:[live]查看堆內存中的對象的狀況。若是有大量對象在持續被引用,並無被釋放掉,那就產生了內存泄露,就要結合代碼,把不用的對象釋放掉。 
5.也可使用 jmap -dump:format=b,file=命令將堆信息保存到一個文件中,再借助jhat命令查看詳細內容 
6.在內存出現泄露、溢出或者其它前提條件下,建議多dump幾回內存,把內存文件進行編號歸檔,便於後續內存整理分析。

性能監控工具命令:jstat

用法講解

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
  • 1

參數解釋: 
Option — 選項,咱們通常使用 -gcutil 查看gc狀況 
vmid — VM的進程號,即當前運行的java進程號 
interval– 間隔時間,單位爲秒或者毫秒 
count — 打印次數,若是缺省則打印無數次 
參數 interval 和 count 表明查詢間隔和次數,若是省略這兩個參數,說明只查詢一次。

示例: 
Jstat –gc 4100 250 5 
這裏寫圖片描述
上圖中參數的意思:

S0C 年輕代中第一個survivor(倖存區)的容量 (字節) 
S0U 年輕代中第一個survivor(倖存區)目前已使用空間 (字節) 
EC 年輕代中Eden(伊甸園)的容量 (字節) 
EU 年輕代中Eden(伊甸園)目前已使用空間 (字節) 
OU Old代目前已使用空間 (字節) 
PC Perm(持久代)的容量 (字節) 
PU Perm(持久代)目前已使用空間 (字節) 
YGC 從應用程序啓動到採樣時年輕代中gc次數 
FGC 從應用程序啓動到採樣時old代(全gc)gc次數 
FGCT 從應用程序啓動到採樣時old代(全gc)gc所用時間(s) 
GCT 從應用程序啓動到採樣時gc用的總時間(s)

Jstat –class 4100 250 5 顯示加載class的數量,及所佔空間等信息。 
這裏寫圖片描述

Loaded 裝載的類的數量 
Unloaded 卸載類的數量 
Bytes 卸載類的字節數 
Time 裝載和卸載類所花費的時間

jstat -compiler 顯示VM實時編譯的數量等信息 
這裏寫圖片描述

Compiled 編譯任務執行數量 
Invalid 編譯任務執行失效數量 
Time 編譯任務消耗時間 
FailedType 最後一個編譯失敗任務的類型 
FailedMethod 最後一個編譯失敗任務所在的類及方法

Jstat –gccapacity 4100 
這裏寫圖片描述

NGCMN 年輕代(young)中初始化(最小)的大小(字節) 
NGC 年輕代(young)中當前的容量 (字節) 
S0C 年輕代中第一個survivor(倖存區)的容量 (字節) 
S1C 年輕代中第二個survivor(倖存區)的容量 (字節) 
EC 年輕代中Eden(伊甸園)的容量 (字節) 
OGCMN old代中初始化(最小)的大小 (字節) 
OGCMX old代的最大容量(字節) 
OGC old代當前新生成的容量 (字節) 
OC Old代的容量 (字節) 
PGCMN perm代中初始化(最小)的大小 (字節) 
PGCMX perm代的最大容量 (字節) 
PGC perm代當前新生成的容量 (字節) 
PC Perm(持久代)的容量 (字節) 
YGC 從應用程序啓動到採樣時年輕代中gc次數 
FGC 從應用程序啓動到採樣時old代(全gc)gc次數

參考資料

【Java命令學習系列(二)-Jstack】http://www.hollischuang.com/archives/110 
【Java命令學習系列(三)—Jmap】http://www.hollischuang.com/archives/303 
【Java命令學習系列(四)—jstat】http://www.hollischuang.com/archives/481

相關文章
相關標籤/搜索