Java常用命令:jps、jstack、jmap、jstat(帶有例項教程)
一、常用命令:
在JDK的bin目彔下,包含了java命令及其他實用工具。
jps:檢視本機的Java中程序資訊。
jstack:列印執行緒的棧資訊,製作執行緒Dump。
jmap:列印記憶體對映,製作堆Dump。
jstat:效能監控工具。
jhat:記憶體分析工具。
jconsole:簡易的視覺化控制檯。
jvisualvm:功能強大的控制檯。
二、認識Java Dump:
什麼是Java Dump?
Java虛擬機器的執行時快照。將Java虛擬機器執行時的狀態和資訊儲存到檔案。
執行緒Dump,包含所有執行緒的執行狀態。純文字格式。
堆Dump,包含執行緒Dump,幵包含所有堆物件的狀態。二進位制格式。
Java Dump有什麼用?
補足傳統Bug分析手段的不足: 可在任何Java環境使用;資訊量充足。 針對非功能正確性的Bug,主要為:多執行緒幵發、記憶體洩漏。
製作Java Dump
使用Java虛擬機制作Dump
指示虛擬機器在發生記憶體不足錯誤時,自動生成堆Dump
-XX:+HeapDumpOnOutOfMemoryError
使用圖形化工具製作Dump
使用JDK(1.6)自帶的工具:Java VisualVM。
使用命令列製作Dump
jstack
:列印執行緒的棧資訊,製作執行緒Dump。
jmap
:列印記憶體對映,製作堆Dump。
步驟:
- 檢查虛擬機器版本(java -version)
- 找出目標Java應用的程序ID(jps)
- 使用jstack命令製作執行緒Dump• Linux環境下使用kill命令製作執行緒Dump
- 使用jmap命令製作堆Dump
檢視Java程序:jps
用法介紹
jps命令:顯示所有程序號和短的類名稱
Jps –q 命令:只顯示程序號
Jps –l 用於傳輸主函式的完整路徑
Jps –v 顯示傳遞給Java虛擬機器的引數(感覺這個命令才是完美,把虛擬機器的一些引數全都打印出來)
檢視執行緒堆疊命令:jstack命令
Jstack命令主要用來檢視Java執行緒的呼叫堆疊的,可以用來分析執行緒問題(如死鎖)。談到執行緒,在Java裡面,執行緒一共有6中狀態
- New 新建 ————- 不會出現在dump中
- Runnable 正在執行中——–在虛擬機器內執行
- Blocked 阻塞————受阻塞,並等待監視器鎖
- Waiting 等待————無限期等待另一個執行緒執行特定操作
- Timed_waiting 超時等待————有時限等待另一個執行緒的操作
- Terminated 終止/結束————已退出的
Monitor
在多執行緒的 JAVA程式中,實現執行緒之間的同步,就要說說 Monitor。 Monitor是 Java中用以實現執行緒之間的互斥與協作的主要手段,它可以看成是物件或者 Class的鎖。每一個物件都有,也僅有一個 monitor。下 面這個圖,描述了執行緒和 Monitor之間關係,以 及執行緒的狀態轉換圖:
進入區(Entrt Set):
表示執行緒通過synchronized要求獲取物件的鎖。如果物件未被鎖住,則迚入擁有者;否則則在進入區等待。一旦物件鎖被其他執行緒釋放,立即參與競爭。
擁有者(The Owner):
表示某一執行緒成功競爭到物件鎖。
等待區(Wait Set):
表示執行緒通過物件的wait方法,釋放物件的鎖,並在等待區等待被喚醒。
從圖中可以看出,一個 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) {
.........
}
呼叫修飾
表示執行緒在方法呼叫時,額外的重要的操作。執行緒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
通過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
通過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
通過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
}
}
}
先利用 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);
}
}
}
我們能看到:
執行緒的狀態: 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();
}
執行輸出:
上圖已經鎖死,只要兩個執行緒都啟動起來,必定會發生死鎖。這個時候趕緊拿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
指定程序號(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>]]
引數解釋:
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次數
jstack是java虛擬機器自帶的一種堆疊跟蹤工具。
功能
jstack用於生成java虛擬機器當前時刻的執行緒快照。執行緒快照是當前java虛擬機器內每一條執行緒正在執行的方法堆疊的集合,生成執行緒快照的主要目的是定位執行緒出現長時間停頓的原因,如執行緒間死鎖、死迴圈、請求外部資源導致的長時間等待等。 執行緒出現停頓的時候通過jstack來檢視各個執行緒的呼叫堆疊,就可以知道沒有響應的執行緒到底在後臺做什麼事情,或者等待什麼資源。 如果java程式崩潰生成core檔案,jstack工具可以用來獲得core檔案的java stack和native stack的資訊,從而可以輕鬆地知道java程式是如何崩潰和在程式何處發生問題。另外,jstack工具還可以附屬到正在執行的java程式中,看到當時執行的java程式的java stack和native stack的資訊, 如果現在執行的java程式呈現hung的狀態,jstack是非常有用的。
So,jstack命令主要用來檢視Java執行緒的呼叫堆疊的,可以用來分析執行緒問題(如死鎖)。
執行緒狀態
想要通過jstack命令來分析執行緒的情況的話,首先要知道執行緒都有哪些狀態,下面這些狀態是我們使用jstack命令檢視執行緒堆疊資訊時可能會看到的執行緒的幾種狀態:
NEW,未啟動的。不會出現在Dump中。
RUNNABLE,在虛擬機器內執行的。
BLOCKED,受阻塞並等待監視器鎖。
WATING,無限期等待另一個執行緒執行特定操作。
TIMED_WATING,有時限的等待另一個執行緒的特定操作。
TERMINATED,已退出的。
Monitor
在多執行緒的 JAVA程式中,實現執行緒之間的同步,就要說說 Monitor。Monitor是 Java中用以實現執行緒之間的互斥與協作的主要手段,它可以看成是物件或者 Class的鎖。每一個物件都有,也僅有一個 monitor。下 面這個圖,描述了執行緒和 Monitor之間關係,以 及執行緒的狀態轉換圖:
進入區(Entrt Set):表示執行緒通過synchronized要求獲取物件的鎖。如果物件未被鎖住,則迚入擁有者;否則則在進入區等待。一旦物件鎖被其他執行緒釋放,立即參與競爭。
擁有者(The Owner):表示某一執行緒成功競爭到物件鎖。
等待區(Wait Set):表示執行緒通過物件的wait方法,釋放物件的鎖,並在等待區等待被喚醒。
從圖中可以看出,一個 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) {
.........
}
呼叫修飾
表示執行緒在方法呼叫時,額外的重要的操作。執行緒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
通過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
通過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
通過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)
執行緒Dump的分析
原則
結合程式碼閱讀的推理。需要執行緒Dump和原始碼的相互推導和印證。
造成Bug的根源往往丌會在呼叫棧上直接體現,一定格外注意執行緒當前呼叫之前的所有呼叫。
入手點
進入區等待
"d&a-3588" daemon waiting for monitor entry [0x000000006e5d5000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()
- waiting to lock <0x0000000602f38e90> (a java.lang.Object)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()
執行緒狀態BLOCKED,執行緒動作wait on monitor entry,呼叫修飾waiting to lock總是一起出現。表示在程式碼級別已經存在衝突的呼叫。必然有問題的程式碼,需要儘可能減少其發生。
同步塊阻塞
一個執行緒鎖住某物件,大量其他執行緒在該物件上等待。
"blocker" runnable
java.lang.Thread.State: RUNNABLE
at com.jiuqi.hcl.javadump.Blocker$1.run(Blocker.java:23)
- locked <0x00000000eb8eff68> (a java.lang.Object)
"blockee-11" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)
"blockee-86" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run