查詢佔用資源高的JAVA程式碼

昀溪發表於2018-07-29

1. /tmp/hsperfdata_$USER目錄

$USER是啟動JAVA程式的使用者,這裡儲存的所有使用者啟動的JAVA程式。

這些都JAVA程式的PID,裡面存放的是JVM程式資訊。你所用的jsp、jstack、jmap這些工具都會讀取這個目錄中對應PID的檔案獲取連線資訊。
有時候你會發現這樣的錯誤

這種情況是你使用的是一個JAVA的執行緒號而不是一個程式號。因為jstack、jps、jmap這些工具都是使用程式號的。
如果你提供了一個根本不存在的程式號呢?它會告訴你無此程式。

這種情況是你使用的是一個JAVA的執行緒號而不是一個程式號。因為jstack、jps、jmap這些工具都是使用程式號的。
如果你提供了一個根本不存在的程式號呢?它會告訴你無此程式。

2. 如何查詢消耗資源的程式碼

透過top命令獲取消耗資源最大的PID號

透過top –p PID –H來檢視指定程式中最消耗資源的執行緒

把執行緒ID轉換為16進位制

printf '0x%x\n' PID

查詢程式碼

如果同一個JAVA程式中有多個佔用CPU資源多的執行緒,那麼你就把執行緒號儲存到一個檔案中,一行一個號。然後執行下面的命令.
找到執行緒號,轉換成十六進位制儲存到檔案裡

儲存堆疊資訊到檔案

查詢,寫一個迴圈程式查詢

while read LINE; do grep $LINE /tmp/stock.txt ; done < /tmp/threadNum.txt

欄位中第一個引號欄位就是JAVA執行緒的名字。由於我這裡其實只是展示一下操作過程實際上並沒有消耗CPU高的執行緒,你會看到比較少的資訊,如果真的有消耗CPU高的執行緒,這裡會有很多同名的Java執行緒名稱。也不能說是名稱完全一樣只是主名稱相同後面還是有區分的。

3. 堆疊資訊說明

prio=N 表示執行緒的優先順序別
os_prio=N 表示執行緒的作業系統優先順序別
tid= 表示執行緒ID
nid= 表示作業系統影視的執行緒ID,非常關鍵,你在top –H –p PID 檢視的數字轉換為十六進位制就是這個

狀態 說明
New 執行緒物件剛剛建立時的狀態,此時不可執行
Runnable 表示執行緒具備所有執行條件,在佇列中等待CPU排程
Running 正在執行
Wait on condition 該執行緒在等待某個條件發生,發生後就可以執行,但具體什麼條件需要進一步檢視。最常見的就是執行緒在等待網路的讀寫,比如網路資料沒有準備好,執行緒處於等待狀態,一旦資料準備好執行緒會被重新啟用。
Waiting for monitor entry和In Object.wait()

Monitor是JAVA中實現執行緒互斥與協調的手段,可以看成物件或者class的鎖。每個物件都有,也僅有一個monitor。每個Monitor在某個時刻只能被一個執行緒擁有,該執行緒叫做Active Thread,而其他執行緒叫做“Waiting Tread”,分別在2個佇列中“Entry Set”和“Wait Set”裡面。在前者佇列的執行緒狀態時“Waiting for monitor entry”,在後者佇列的執行緒狀態是“in Object.wait()”

Wating on monitor entry:正在等待鎖
In Object.wait():獲取鎖以後又執行了obj.wait()放棄鎖

 

 

 

 

 

 

 

 

4. 關於“Unable to open socket file: target process not responding or HotSpot VM not loaded”問題

遇到這個問題可能有幾個原因:

  1. 執行該命令的使用者賬號和啟動指定程式的使用者賬號不一致。也就是PID  145784這個程式是透過其他賬號啟動的,而不是當前你用的賬號
  2. /tmp/hsperfdata_$USER這個目錄裡的內容被清理,這裡放的就是啟動程式的程式號,由於是臨時目錄有可能Linux系統定期清理導致程式號檔案沒有了,所以會列印堆疊資訊失敗。因為jps和jstack等工具會讀取這個目錄裡面指定程式號的PID檔案獲取連線資訊。
  3. 確保你使用的命令的JDK版本和執行JAVA程式的JDK版本一致。

其實透過第二條就知道為什麼第一條存在,因為不同使用者會有不同目錄,你用root賬號雖然許可權大,但是它會讀取/tmp/hsperfdata_root目錄,而你需要列印堆疊的程式是用其他賬號啟動的,所以用root會報錯。
切換賬號後列印成功

 

相關文章