天天看點

jvm cpu占用過高執行個體以及排查方法

起因

在項目現場發現,程式運作的過程中,發現會時不時有cpu占用400%以上的情況,而通過界面很難定位到觸發了哪裡導緻的,不能縮小分析範圍。

收集資料

于是使用了以下幾種方式采集資料:

1、對jar包配置jmx參數進行暴露,在重新開機即可使用jdk的jvisualvm.exe進行遠端監控

2、下載下傳阿裡的arthas進行監控。

以上兩種方式的使用方法就不多說了,請大家自行百度。

分析

一般對于jvm問題,不外乎就兩種表現現象,一種就是堆記憶體占太多沒有被釋放,一種就是cpu占用過高。

堆記憶體太多導緻堆溢出的原因有很多種,大概就是資源沒釋放,存在記憶體的資料量過大等問題導緻。而cpu過高一般是程式在執行某段代碼執行過長,且一直在計算,要麼進入了死循環,要麼計算的量太大,導緻占用cpu過高。

當然還有死鎖的現象,不過這種得看具體線程的狀态。

先從大點分析,cpu過高,應該資料計算類問題,那麼就得看是那個線程占用了cpu,通過arthas的dashboard檢視某個線程後,使用thread 線程号,即可看出該線程運作的代碼到哪一步,檢視後發現是停在了某個for循環代碼中,于是檢查那個for循環,發現for(int i=1;i<pages;i++) 這個pages的值是由int pages=(int)Math.ceil((double)total/(double)pageSize)來的,而當pageSize=0時,就會出現int的最大整數2147483647,這個數字使得在for循環轉了半天。

那為什麼pageSize會等于0呢,是因為前端傳入了pageSize為0,而後端沒有判斷如果為0則給預設值的情況,是以這塊就直接過了,那繼續問下去,為什麼前端會傳0呢,按道理一般寫法會給分頁一個預設值的,了解到後是因為前端想拿所有的資料,而之前對接時想拿所有資料就是這樣傳的,因為pagehelper的分頁如果接收pageSize和pageNum為0的情況下,會查所有記錄。那為啥這次想擷取所有資料又是采用了分頁的做法來擷取呢,不搞分頁不就行了嗎?後面得知是後端這麼設計,但前端發現後沒提出異議,直接就這麼做了,不過與本文就沒太大關系了。

結論

在修改了接口後,線上的cpu占用過高問題就結束了,本次隻用了arthas的一部分功能,實際上很多功能還沒能用到,看官方介紹說明還是很有用處的,有需要的同學可以自己模拟錯誤情況試一下。

jvm