轉(zhuǎn)載請注明轉(zhuǎn)自:https://showme.codes/2017-02-17/endless-loop-cpu100/
導(dǎo)致CPU100%的原因很多,而程序中出現(xiàn)死循環(huán)就是原因之一。然而,并不是每個人在工作中都有機(jī)會踩中這個坑。我就是其中一個沒踩過的。人生似乎有些不完整。
所以,我做了一個很重要的決定:在程序中寫一個死循環(huán)。看看會發(fā)生什么事情。
當(dāng)然,不是在生產(chǎn)環(huán)境。?? 我搭建了一個實驗環(huán)境來做實驗。只是這個實驗環(huán)境不僅可以用于這個死循環(huán)實驗。以下是這個環(huán)境的結(jié)構(gòu)圖:
還是老樣子,使用Vagrant + Virtualbox + Ansible自動化搭環(huán)境。代碼及搭建步驟在文末。
我們會寫一個簡單的Spring MVC 應(yīng)用,然后其中一個接口里會有死循環(huán)代碼:
@RequestMapping(value = "/loop", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public void endlessLoop() {
int i = 0;
while (true) {
System.out.println(i += 1);
}
}
以下是我自己嘗試找出這個死循環(huán)的過程。
使用top,查看是哪個進(jìn)程的問題
我請求一次:http://192.168.88.10:9898/web/loop
然后,我打開新窗口,又請求一次
這里,我好奇CPU沒有到200%。一直在120%和130%之間。P.S. 我一定是某個知識點不牢固,要不,不會有這個疑問。
堆空間
因為不涉及JVM堆空間問題,執(zhí)行 jstat -gcutil 32593 1s
沒看出什么問題。32593為Java進(jìn)程ID,1s指1秒抽樣一次。
棧
堆沒問題,就看看是哪個線程占用得高。
-
列出java進(jìn)程的線程,
top -H -p <java 進(jìn)程pid>
找到CPU占用高的線程PID 將jvm的棧dump下來
jstack -l <其中一個線程PID> >> stack.log
,這里我選3596。-
在日志中,找到相應(yīng)的線程
我們需要從棧日志中找到相應(yīng)的線程,但由于棧日志中使用的16進(jìn)制,但是top中的PID又是10進(jìn)制,所以,需要手工將10進(jìn)制的PID轉(zhuǎn)成16進(jìn)制。3596的16進(jìn)制轉(zhuǎn)是0xe0c
less stack.log 然后搜0xe0c
小結(jié)
好吧。我沒有因為寫這個死循環(huán)去看10小時的無聊電影。
附錄:
- 代碼:performance-labs
- 準(zhǔn)備環(huán)境:虛擬機(jī)的賬號密碼都是vagrant
- git clone git@github.com:zacker330/performance-labs.git
- vagrant up
- download jdk8 to ansible/roles/jdk8/files: https://pan.baidu.com/s/1bpxfpvD
- ansible-playbook ./ansible/playbook.yml -i ./ansible/inventory -u vagrant -k
- ansible-playbook ./ansible/init-mysql.yml -i ./ansible/inventory -u vagrant -k
- cd ansible;chmode +x ./buildwarfile.sh;./buildwarfile.sh --> 將會提示輸入vagrant密碼
- 訪問:http://192.168.88.10:9898/web/