1. 程式人生 > >線上Java程式佔用 CPU 過高,請說一下排查方法?

線上Java程式佔用 CPU 過高,請說一下排查方法?

> 我是風箏,公眾號「古時的風箏」,一個兼具深度與廣度的程式設計師鼓勵師,一個本打算寫詩卻寫起了程式碼的田園碼農! 文章會收錄在 [JavaNewBee](https://github.com/huzhicheng/JavaNewBee) 中,更有 Java 後端知識圖譜,從小白到大牛要走的路都在裡面。 這個問題可以說是 Java 面試的高頻面試題了,有很多面試官都喜歡問這個問題,問題可能是下面這樣的。 > 線上一臺伺服器 CPU 使用率100% 了,如果你碰到這樣的情況,如何排查並找到問題原因? 這就是一個套路題,所謂套路題就是有標準的套路解法的,掌握了套路,不僅能解決面試官,還能解決問題。不然真的就掉進套路里了。 當我們真碰到這個問題的時候應該怎麼排查呢? ## 模擬一個高 CPU 場景 先用一段程式建立幾個執行緒,將其中一個執行緒設定成高 CPU 使用率的。 ```java public static void main(String[] args) { for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(30 * 60 * 1000); }catch (Exception e){ e.printStackTrace(); } }); thread.setName("thread-" + i); thread.start(); } Thread highCpuThread = new Thread(() -> { int i = 0; while (true) { i++; } }); highCpuThread.setName("HighCpu"); highCpuThread.start(); } ``` 執行這段程式後,前面 10 個執行緒都處於休眠狀態,只有最後一個執行緒會持續的佔用 CPU 。 執行這段程式,然後就可以開始一些列的操作來發現問題原因了。 ## 排查步驟 ### 第一步,使用 top 找到佔用 CPU 最高的 Java 程序 在真實環境中,首先要確認是不是 Java 程式造成的,如果有系統監控工具,可能會直接在預警資訊裡告訴你是有哪個程序造成的,但也有可能不知道,需要我們手動排查。 如果是在面試場景中,這個問題可能不需要確認,畢竟 Java 面試,面試官可能直接就告訴你是 Java 佔用的 CPU 過高。 這一步也非常簡單,就是一個 `top`命令而已,基本上所有同學都用過這個命令吧。 ![](https://hexo.moonkite.cn/blog/image-20201101151907692.png) 使用 `top`命令發現佔用 CPU 99.7% 的執行緒是 Java 程序,程序 PID 為 `13731`。 ### 第二步,用 `top -Hp` 命令檢視佔用 CPU 最高的執行緒 上一步用 `top`命令找到了那個 Java 程序。那一個程序中有那麼多執行緒,不可能所有執行緒都一直佔著 CPU 不放,這一步要做的就是揪出這個罪魁禍首,當然有可能不止一個。 執行`top -Hp pid`命令,pid 就是前面的 Java 程序,我這個例子中就是 `13731` ,完整命令為: `top -Hp 13731`,執行之後的效果如下 ![](https://hexo.moonkite.cn/blog/image-20201101153932176.png) 可以看到佔用 CPU 最高的那個執行緒 PID 為 `13756`。 然後將 `13756`轉換為 16 進位制的,後面會用到,可以用線上進位制轉換的網站直接轉換,轉換結果為 `0x35bc` ### 第三步,儲存執行緒棧資訊 當前 Java 程式的所有執行緒資訊都可以通過 `jstack`命令檢視,我們用`jstack`命令將第一步找到的 Java 程序的執行緒棧儲存下來。 ````shell jstack 13731 > thread_stack.log ```` ### 第四步,線上程棧中查詢最貴禍首的執行緒 第二步已經找到了這個罪魁禍首的執行緒 PID,並把它轉換成了 16 進位制的,第三步儲存下來的執行緒棧中有所有執行緒的 PID 16 進位制資訊,我們線上程棧中查詢這個16進位制的執行緒 id (`0x35bc`)。 ![](https://hexo.moonkite.cn/blog/image-20201101193950261.png) 怎麼樣,現在一目瞭然了,執行緒名稱、執行緒狀態、以及哪行程式碼消耗了最多的 CPU 都很清楚了。 *** **這位英俊瀟灑的少年,如果覺得還不錯的話,給個推薦可好!** 公眾號「古時的風箏」,Java 開發者,全棧工程師,bug 殺手,擅長解決問題。 一個兼具深度與廣度的程式設計師鼓勵師,本打算寫詩卻寫起了程式碼的田園碼農!堅持原創乾貨輸出,你可選擇現在就關注我,或者看看歷史文章再關注也不遲。長按二維碼關注,跟我一起變優秀! ![](https://img2020.cnblogs.com/blog/273364/202008/273364-20200807093211558-1258890