1、背景
在服務器上執(zhí)行某個任務時,系統(tǒng)突然運行緩慢,top 發(fā)現(xiàn)cpu飆升,一度接近100%,最終導致服務假死。
2、CPU 使用率怎么計算?
CPU% = 1 – idleTime / sysTime * 100
3、問題分析
#查看所有進程占系統(tǒng)cpu的排序,極大可能排第一的就是自己的java進程,pid就是進程號。1、top #查看java進程下的所有線程占cpu情況。2、top -Hp 進程id #可查看進程堆棧信息3、jstack 進程號 -F當正常輸出的請求不被響應時,強制輸出線程堆棧-m如果調(diào)用到本地方法的話,可以顯示C/C++的堆棧-l除堆棧外,顯示關(guān)于鎖的附加信息,在發(fā)生死鎖時可以用jstack -l pid來觀察鎖持有情況#查找某進程下-》線程id(jstack堆棧信息中的nid)=0xa的線程狀態(tài)4、jstack 進程號 | grep 線程id最后可以把對應堆棧信息導入到log中,進行分析
jstack命令查看對應進程的堆棧信息
3、可能導致的原因
計算密集型的程序是比較耗 CPU 使用率的1、頻繁GC,訪問量高時,有可能造成頻繁的YGC、甚至FGC。當調(diào)用量大時,內(nèi)存分配過快,就會造成GC線程不停的執(zhí)行,導致CPU飆高2、代碼中有大量消耗CPU的操作,導致CPU過高,系統(tǒng)運行緩慢; #例如某些復雜算法,甚至算法BUG,無限循環(huán)遞歸等等 3、由于鎖使用不當,導致死鎖4、序列化與反序列化,后文中舉了一個真實的案例,程序執(zhí)行xml解析的時,調(diào)用量增大的情況下,導致了CPU被打滿5、加密、解密6、正則表達式校驗,曾經(jīng)線上發(fā)生一次血案,正則校驗將CPU打滿。大概原因是:Java 正則表達式使用的引擎實現(xiàn)是 NFA 自動機,這種引擎在進行字符匹配會發(fā)生回溯(backtracking)7、線程上下文切換、當啟動了很多線程,而這些線程都處于不斷的阻塞狀態(tài)(鎖等待、IO等待等)和執(zhí)行狀態(tài)的變化過程中。當鎖競爭激烈時,很容易出現(xiàn)這種情況
4、常見的一些問題(來源于其他大佬的總結(jié))
4-1.while的無限循環(huán)會導致CPU使用率飆升嗎?
是。
首先,無限循環(huán)將調(diào)用CPU寄存器進行計數(shù),此操作將占用CPU資源。那么,如果線程始終處于無限循環(huán)狀態(tài),CPU是否會切換線程?
除非操作系統(tǒng)時間片到期,否則無限循環(huán)不會放棄占用的CPU資源,并且無限循環(huán)將繼續(xù)向系統(tǒng)請求時間片,直到系統(tǒng)沒有空閑時間來執(zhí)行任何其他操作。
4-2.頻繁的Young GC會導致CPU占用率飆升嗎?
是。
Young GC本身就是JVM用于垃圾收集的操作,它需要計算內(nèi)存和調(diào)用寄存器。因此,頻繁的Young GC必須占用CPU資源。
讓我們來看一個現(xiàn)實世界的案例。for循環(huán)從數(shù)據(jù)庫中查詢數(shù)據(jù)集合,然后再次封裝新的數(shù)據(jù)集合。如果內(nèi)存不足以存儲,JVM將回收不再使用的數(shù)據(jù)。因此,如果所需的存儲空間很大,您可能會收到CPU使用率警報。
4-3.具有大量線程的應用程序的CPU使用率是否較高?
不是。
如果通過jstack檢查系統(tǒng)線程狀態(tài)時線程總數(shù)很大,但處于Runnable和Running狀態(tài)的線程數(shù)不多,則CPU使用率不一定很高。
我遇到過這樣一種情況:系統(tǒng)線程的數(shù)量是1000+,其中超過900個線程處于BLOCKED和WAITING狀態(tài)。該線程占用很少的CPU。
但是大多數(shù)情況下,如果線程數(shù)很大,那么常見的原因是大量線程處于BLOCKED和WAITING狀態(tài)。
4-4.對于CPU占用率高的應用程序,線程數(shù)是否較大?
不是。
高CPU使用率的關(guān)鍵因素是計算密集型操作。如果一個線程中有大量計算,則CPU使用率也可能很高。這也是數(shù)據(jù)腳本任務需要在大規(guī)模集群上運行的原因。
4-5.處于BLOCKED狀態(tài)的線程是否會導致CPU占用率飆升?
不會。
CPU使用率的飆升更多是由于上下文切換或過多的可運行狀態(tài)線程。處于阻塞狀態(tài)的線程不一定會導致CPU使用率上升。
4-6.如果分時操作系統(tǒng)中CPU的值us或sy值很高,這意味著什么?
可以使用命令查找CPU的值us和sy值top,如以下示例所示:
us:用戶空間占用CPU的百分比。簡單來說,高我們是由程序引起的。通過分析線程堆棧很容易找到有問題的線程。
sy:內(nèi)核空間占用CPU的百分比。當sy為高時,如果它是由程序引起的,那么它基本上是由于線程上下文切換。