轉(zhuǎn)載請(qǐng)注明轉(zhuǎn)自:https://showme.codes/2017-02-17/endless-loop-cpu100/
導(dǎo)致CPU100%的原因很多润脸,而程序中出現(xiàn)死循環(huán)就是原因之一蜕猫。然而旷太,并不是每個(gè)人在工作中都有機(jī)會(huì)踩中這個(gè)坑。我就是其中一個(gè)沒踩過的赊抖。人生似乎有些不完整演闭。
所以吨掌,我做了一個(gè)很重要的決定:在程序中寫一個(gè)死循環(huán)斩个】韬迹看看會(huì)發(fā)生什么事情驯杜。
當(dāng)然受啥,不是在生產(chǎn)環(huán)境。?? 我搭建了一個(gè)實(shí)驗(yàn)環(huán)境來做實(shí)驗(yàn)。只是這個(gè)實(shí)驗(yàn)環(huán)境不僅可以用于這個(gè)死循環(huán)實(shí)驗(yàn)滚局。以下是這個(gè)環(huán)境的結(jié)構(gòu)圖:
還是老樣子居暖,使用Vagrant + Virtualbox + Ansible自動(dòng)化搭環(huán)境。代碼及搭建步驟在文末藤肢。
我們會(huì)寫一個(gè)簡(jiǎn)單的Spring MVC 應(yīng)用太闺,然后其中一個(gè)接口里會(huì)有死循環(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);
}
}
以下是我自己嘗試找出這個(gè)死循環(huán)的過程。
使用top嘁圈,查看是哪個(gè)進(jìn)程的問題
我請(qǐng)求一次:http://192.168.88.10:9898/web/loop
然后省骂,我打開新窗口,又請(qǐng)求一次
這里最住,我好奇CPU沒有到200%钞澳。一直在120%和130%之間。P.S. 我一定是某個(gè)知識(shí)點(diǎn)不牢固涨缚,要不轧粟,不會(huì)有這個(gè)疑問。
堆空間
因?yàn)椴簧婕癑VM堆空間問題脓魏,執(zhí)行 jstat -gcutil 32593 1s
沒看出什么問題兰吟。32593為Java進(jìn)程ID,1s指1秒抽樣一次茂翔。
棧
堆沒問題混蔼,就看看是哪個(gè)線程占用得高。
-
列出java進(jìn)程的線程珊燎,
top -H -p <java 進(jìn)程pid>
將jvm的棧dump下來
jstack -l <其中一個(gè)線程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
小結(jié)
好吧烹卒。我沒有因?yàn)閷戇@個(gè)死循環(huán)去看10小時(shí)的無聊電影闷盔。
附錄:
- 代碼:performance-labs
- 準(zhǔn)備環(huán)境:虛擬機(jī)的賬號(hào)密碼都是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 --> 將會(huì)提示輸入vagrant密碼
- 訪問:http://192.168.88.10:9898/web/