JAVA 應用 CPU 使用率為什麼飈升?
我的疑惑
一個 while 死迴圈,會不會引起 CPU 使用率飈升?
頻繁 Young GC 會不會引起 CPU 使用率飈升?
執行緒數很高的應用,CPU 使用率一定高麼?
CPU 使用率高的應用,執行緒數一定高麼?
BLOCKED 狀態的執行緒會不會引起 CPU 使用率飈升?
分時作業系統 CPU 是耗費 us ? 還是耗費 sy ?
我的思考
CPU 使用率怎麼算?
CPU% = 1 - idleTime / sysTime * 100
-
idleTime:CPU處於空閒狀態的時間
-
sysTime:CPU處於使用者態和核心臺的時間總和
CPU 使用率跟啥有關係?
我們常聽說計算密集型的程式是比較耗 CPU 使用率的。
那 JAVA 應用中哪些操作是比較耗 CPU 使用的?
列舉下日常程式中常見的耗CPU的操作:
-
頻繁GC,訪問量高時,有可能造成頻繁的GC、甚至FGC。當呼叫量大時,記憶體分配過快,就會造成GC執行緒不停的執行,導致CPU飆高。
-
序列化與反序列化,後文中舉了一個真實的案例,程式執行xml解析的時,呼叫量增大的情況下,導致了CPU被打滿。
-
加密、解密。
-
正則表示式校驗,曾經線上發生一次血案,正則校驗將CPU打滿。大概原因是:Java 正則表示式使用的引擎實現是 NFA 自動機,這種引擎在進行字元匹配會發生回溯(backtracking)。
-
執行緒上下文切換、當啟動了很多執行緒,而這些執行緒都處於不斷的阻塞狀態(鎖等待、IO等待等)和執行狀態的變化過程中。當鎖競爭激烈時,很容易出現這種情況。
-
某些執行緒在做無阻塞的運算,簡單的例子while(true)中不停的做運算,沒有任何阻塞。寫程式時,如果需要做很久的計算,可以適當將程式sleep下。
CPU 與程序、執行緒有關係麼?
現在分時作業系統是通過循輪方式分配時間片進行 程序 排程的,如果程序在等待或阻塞,不會造成 CPU 資源使用。執行緒稱為輕程序,共享程序資源,關於執行緒的排程,CPU 對於執行緒也是分時排程。而在 Java 中,執行緒的呼叫由 JVM 負責,執行緒的排程一般有兩種模式,分時排程和搶佔式排程。
我的解惑
一個 while 死迴圈,會不會引起 CPU 使用率飈升?
會的。先不說別的,死迴圈會呼叫 CPU 暫存器進行計數,這個操作就會佔用 CPU。其次,如果執行緒一直處於死迴圈狀態,CPU 呼叫會進行執行緒切換麼?
死迴圈不會讓出 CPU,除非作業系統時間片到期,但死迴圈會不斷向系統申請時間片,直到系統沒有空閒時間做別的事情。
這個問題在 stackoverflow 也有人提問:why does an infinite loop of the unintended kind increase the CPU use?
地址: ofollow,noindex" target="_blank">https://stackoverflow.com/questions/2846165/why-does-an-infinite-loop-of-the-unintended-kind-increase-the-cpu-use
頻繁 Young GC 會不會引起 CPU 使用率飈升?
會的。Young GC 本身是 JVM 進行垃圾回收的操作,會計算記憶體和呼叫暫存器,頻繁 Young GC 一定是會佔用 CPU。
之前有個一個案例,for 迴圈從資料庫查詢資料集合,二次封裝新的資料集合,這時如果量比較大時,記憶體沒有足夠的空間儲存,那麼 JVM 就會 GC 回收那些不再使用的資料,因此量大的時候,就會收到 CPU 使用率報警。
執行緒數很高的應用,CPU 使用率一定高麼?
不會。通過 jstack 檢視系統執行緒狀態,檢視整個執行緒數很多,但 Runable 和 Running 狀態的執行緒不多,這時 CPU 使用率不一定會高。
之前有過一個案例,檢視系統執行緒數 1000+,jstack 分析 900多個執行緒是 BLOCKED 和 WAITING 狀態的,這種執行緒是不會佔用 CPU 的。
如果執行緒數很高,其實大多數原因是死鎖,大量執行緒處於 BLOCKED 和 WAITING 狀態。
CPU 使用率高的應用,執行緒數一定高麼?
不會。同上,CPU 使用率高的關鍵因素還是計算密集型操作,一個執行緒如果有大量計算,也會造成 CPU 使用率高,也是現在為什麼一個大資料指令碼任務,要大規模叢集共同運算才能執行的原因。
BLOCKED 狀態的執行緒會不會引起 CPU 使用率飈升?
不一定,CPU使用率的飆升,更多是因為上下文的切換或者runnable狀態執行緒過多導致。Blocked狀態,未必會引起CPU上升。
分時作業系統 CPU us高或者sy高是什麼意思?
通過top命令,我們可以觀察到cpu的us,sy值,示例如下:
-
Us 使用者空間佔用CPU百分比,簡單來說,us高是因為我們的程式導致的,通過分析執行緒堆疊,可以很容易的定位到問題執行緒。
-
Sy 核心空間佔用CPU百分比,sy高的時候,如果是程式問題導致,基本是因為執行緒上下文切換造成的。
我的經驗
平時怎麼定位 CPU 使用率高的原因的?
其實網上有個教程和方法,我簡述我的分析過程。
首先發現某臺應用 CPU 使用率高,一要看先執行緒數、JVM、系統 load 等引數,共同作證。二要列印 jstack,通過工具分析執行緒情況,推薦 fastThread 這個線上的 Thread 分析工具。
以下是線上發生的真實案例,簡要介紹下:
某日晚,突然收到簡訊報警,CPU利用率100%。立刻dump該機器jstack,通過 http://fastthread.io/ 檢視日誌如下:
進一步檢視具體日誌:
通過這段日誌,已經定位到了具體CPU被打滿的方法,接收MQ之後,MQ訊息體為xml,反序列化的時候,造成了CPU飆高。