【bugfix】記一次CPU飆高的排查經歷

目錄

1.定位進程

2.定位線程

3.線程虛擬機棧分析

4.解決方案

4.1 升級JDK

4.2 使用ConcurrentHashMap


1.定位進程

top拿到cpu佔用最高進程的進程號pid=14398

2.定位線程

top -H -p pid 特定進程中的線程

top -H -p 14398

找到最高的線程id:29230、29156、29151、29197、29240、29284、29291

轉換成hex十六進制722e、71e4、71df、720d、7238、7264、726b

3.線程虛擬機棧分析

jstack pid | grep threadId

jstack生成線程快照的目的通常是定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導致的長時間掛起等,都是導致線程長時間停頓的常見原因。pid是進程id,threadId是上個步驟拿到的線程id

jstack 14398 |grep 722e -A 20 --col

上圖就是找到的14398進程的0x722e 線程的棧信息,前幾名的線程棧幾乎都差不多,都是HashMap的get操作。由於我們的服務運行在JDK1.6下,很自然的聯想到HashMap線程不安全,在擴容時併發有可能形成鏈表迴路,導致後續操作遍歷鏈表時有死循環!具體請戳

由此幾乎驗屍完成,就是由於用了線程不安全的HashMap,併發擴容形成鏈表環路,導致get操作遍歷鏈表時形成死循環,導致線程一直不能執行結束,一直在搶佔CPU時間片,導致CPU資源的消耗過大。

4.解決方案

4.1 升級JDK

我們都知道HashMap在1.8fix了擴容時插入鏈表的順序,不會造成迴路了,所以可以通過升級JDK

4.2 使用ConcurrentHashMap

併發容器有鎖控制,不會有多個線程併發修改鏈表,不會形成迴路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章