文章目錄
- 一、背景
- 二、分析步驟
- 三、一個例子
- 1、撰寫demo
- 2、部署demo
- 3、問題現象
- 四、總結
一、背景
Java 應用怎么通過方法定位到代碼的具體步驟,下面通過一個具體的例子來說明,
二、分析步驟
- 使用 TOP 命令找到誰在消耗 CPU 比較高的行程,例如:pid = 1232
- 使用 top -p 1232 單獨監控該行程
- 輸入大寫的 H 列出當前行程下的所有執行緒
- 查看消耗 CPU 比較高的執行緒,并看執行緒編號,例如:2399
- 使用 jstack 1232>pagainfo.dump 獲取當前行程下的 dump 執行緒資訊
- 將第四步獲取的執行緒編號 12399 轉換成 16 進制 306f (printf “%x\n” 12399)
- 根據 306f 在第 5 步獲取的堆疊資訊中查找 tid=0x306 的執行緒
- 定位代碼位置(根據列印出來的堆疊資訊查看代碼所在位置)
注意:
從作業系統列印出的虛擬機的本地執行緒看,本地執行緒數量和 Java 執行緒堆疊中的執行緒數量相同, 說明二者是一一對應的,只不過 java 執行緒中的 nid 中用 16 進制來表示, 而本地執行緒中的 id 用十進制表示,
?
?
三、一個例子
1、撰寫demo
一個 Springboot 例子:
/**
* @author 7d
* @Title: PageIndex
* @Description: 使用命令top-->top -p PID -- H jstack pid
* @date 2019/11/9 / 10:23
*/
@Log4j2
@Controller
public class PageIndexController {
/**
* 測驗demo
* @return
*/
@GetMapping("/7d")
@ResponseBody
public Object topDemo() {
StudentInfo stInfo = new StudentInfo();
stInfo.setName("topJava");
stInfo.setAge(30);
stInfo.setDes("冠禮之年測驗java通過top命令查看jvm");
stInfo.setGrade("7DGroup");
for (int i = 0; i < 100000; i++) {
i++;
try {
log.info("my is print" + i);
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return stInfo;
}
/**
* 除錯
* @return
*/
@GetMapping("/7ddemo")
@ResponseBody
public Object topDemo1() {
StudentInfo stInfo = new StudentInfo();
stInfo.setName("topJava");
stInfo.setAge(30);
stInfo.setDes("冠禮之年測驗java通過top命令查看jvm");
stInfo.setGrade("7DGroup");
return stInfo;
}
}
2、部署demo
上傳到 linux 服務器運行:
?
java -jar jdktop-0.0.1-SNAPSHOT.jar

打開瀏覽器訪問:

3、問題現象
可以使用 Jmeter 壓測,方便咱們進行性能定位,也可以使用 idea 簡單發起請求:

點擊請求:

訪問寫好的請求 http://ip:port/7d 后,通過查看日志顯示系統后臺運行,但前端一直處于等待狀態,

?
?
打開 Linux 服務器,敲 top 命令查看消耗 CPU 中的 Java 行程,通過觀察該行程在作業系統中消耗 CPU 不是很高,這里演示下上面操作步驟:

使用命令 top -p PID 即可看到該行程下的執行緒資訊:

接下來使用 jstack 命令進行,打出 dump 資訊
[root@localhost bin]# ./jstack 93114 >/home/7d/7djava.dump

切換到 dump 生成的目錄下:

我們可以下載到本地進行查看或者使用 Jdk 自帶的 jvisualvm 工具查看,這里演示方便直接在 Linux 服務器上打開:
?
[root@localhost 7d]# vim 7djava.dump

這里演示需要,就找到下圖中的 java 執行緒:
?

PID 十進制轉換 16 進制:

在打開 dump 檔案中通過 vim 搜索命令查找:

從上面可以看出目前執行緒正處于 TIMED_WAITING 狀態,表示當前被掛起一段時間,時長為引數中指定的時長,如Thread.sleep(1000),因此該執行緒當前不消耗CPU,
?
這里簡單介紹下執行緒怎么看:


http-nio-8080-exec-11" #30 daemon prio=5 os_prio=0 tid=0x00007fadf8001000 nid=0x16bf8 waiting on condition [0x00007fae6c7d0000]
- 執行緒名稱:“http-nio-8080-exec-11”
- 執行緒優先級:prio=5
- 執行緒對應的本地執行緒id號:nid=0x16bf8
- 執行緒的狀態:waiting
- 執行緒占用記憶體地址:[0x00007fae6c7d0000]
?
?
接下來我們找到代碼的包名與代碼行:

從下面資訊得出:

再次查看原始碼:

四、總結
快速通過執行緒 dump 分析知道程式目前處于什么狀態,就知道怎么下一步如何下手分析,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/294823.html
標籤:java
