JVM: 使用 jstack 命令找出 cpu 飆高的原因
阿新 • • 發佈:2018-12-16
首先新建一個springboot專案,新建一個controller
@RestController public class DeadLockController { private Object lock1 = new Object(); private Object lock2 = new Object(); @GetMapping("/deadlock") public String deadLock() { new Thread(() -> { synchronized (lock1) { try { Thread.sleep(1000); } catch (Exception e) { } synchronized (lock2) { System.out.println("Thread1 over"); } } }).start(); new Thread(() -> { synchronized (lock2) { try { Thread.sleep(1000); } catch (Exception e) { } synchronized (lock1) { System.out.println("Thread2 over"); } } }).start(); return "deadlock"; } @RequestMapping("/loop") public List<Long> loop() { String data = "{\"data\":[{\"partnerid\":]"; return getPartneridsFromJson(data); } public static List<Long> getPartneridsFromJson(String data){ List<Long> list = new ArrayList<Long>(2); if(data == null || data.length() <= 0){ return list; } int datapos = data.indexOf("data"); if(datapos < 0){ return list; } int leftBracket = data.indexOf("[",datapos); int rightBracket= data.indexOf("]",datapos); if(leftBracket < 0 || rightBracket < 0){ return list; } String partners = data.substring(leftBracket+1,rightBracket); if(partners == null || partners.length() <= 0){ return list; } while(partners!=null && partners.length() > 0){ int idpos = partners.indexOf("partnerid"); if(idpos < 0){ break; } int colonpos = partners.indexOf(":",idpos); int commapos = partners.indexOf(",",idpos); if(colonpos < 0 || commapos < 0){ continue; } String pid = partners.substring(colonpos+1,commapos); if(pid == null || pid.length() <= 0){ continue; } try{ list.add(Long.parseLong(pid)); }catch(Exception e){ } partners = partners.substring(commapos); } return list; } }
使用maven把專案打成jar包,然後使用命令:nohup java -jar springboot-0.0.1-SNAPSHOT.jar &
執行專案
先測試死迴圈,開啟地址:http://192.168.0.8:8080/loop ,可以多開幾個頁面,然後使用top命令檢視
可以看到程序5700的cpu飆到快700, load average也一直在 不停上升。
使用命令:
jstack 5700 > 5700.txt
top -p 5700 -H //檢視5700程序的所有執行緒
可以看到5732、5735、5729 等好幾個執行緒cpu都飆到了99%,我們可以看一下 5700.txt中,這些執行緒在幹什麼 。以5732為例,由於5700.txt文字中的程序號都是16進位制的,而5732是十進位制,所以我們把5732轉16進製得到1664。去5700.txt中查詢1664,執行命令 grep -C 10 "1664" 5700.txt
這樣可以很清晰的看到是我們的DeadLockController裡面的方法造成的。
再測試死鎖,先把上一個專案程序關掉,執行命令 kill -9 5700
,再重新執行專案
開啟 http://192.168.0.8:8080/deadlock
在執行命令,用jstack打印出程序的執行緒堆疊資訊,如重啟專案後的程序號是8208,jstack 8208 > 8208.txt
檢視 8208.txt cat 8208.txt
可以看到,檔案裡面已經找到了一處死鎖