前言
本文介紹服務器內運行的 Java 應用產生的 OOM 問題 和 CPU 100% 的問題定位
1. 內存 OOM 問題定位
某Java服務(比如進程id pid 為 3320)出現OOM,常見的原因為:
- 內存分配的確實小了,而正常業務使用了大量的內存
- 某個對象被頻繁申請,卻沒有釋放,內存不斷泄露,導致內存耗盡
- 某個資源被頻繁申請,系統資源耗盡。例如不斷創建線程,不斷發起網絡請求。
資源不夠(也是"給的資源耗盡"),資源申請過多導致資源耗盡,資源申請過多不釋放導致資源耗盡。
以下為使用工具排查方法:
1.1 jmap 確認內存是否分配過小
命令:jmap -heap 3320
可查看新生代,老年代堆內部內存的分配大小以及使用情況。看是否是因為分配的過小
1.2 找到最耗內存的對象
jmap -histo:live 3320 | more
[C is a char[]
[S is a short[]
[I is a int[]
[B is a byte[]
[[I is a int[][]
會以表格的形式顯示存活對象的信息,並按內存大小排序。(num:排名,instances:實例數,bytes:所占內存大小,class name: 類名)上面的輸出中[C對象占用Heap這么多,往往跟String有關,String其內部使用final char[]數組來保存數據的。
對於實例數較多,占用內存大小較多的實例/類,相關的代碼就要針對性review了。上圖占用最多的是[C 占用30M。
如果發現某類對象占用內存很大(例如幾個G),很可能是類對象創建太多,且一直未釋放。例如:
- 申請完資源后,未調用close()或dispose()釋放資源
- 消費者消費速度慢(或停止消費了),而生產者不斷往隊列中投遞任務,導致隊列中任務累積過多
線上執行該命令會強制執行一次fgc。另外還可以dump內存進行分析。
1.3 確認是否是資源耗盡
工具:
- pstree
- netstat
查看進程創建的線程數,以及網絡連接數,如果資源耗盡,也可能出現OOM。
這里介紹另一種方法,通過
- /proc/${PID}/fd
- /proc/${PID}/task
可以分別查看句柄詳情和線程數。
如上圖,sshd共占用了四個句柄
- 0 -> 標准輸入
- 1 -> 標准輸出
- 10 -> 標准錯誤輸出
- 100 -> socket(容易想到是監聽端口)
文件描述符fd。linux中, 每一個進程在內核中,都對應有一個“打開文件”數組,存放指向文件對象的指針,而 fd 是這個數組的下標。 我們對文件進行操作時,系統調用,將fd傳入內核,內核通過fd找到文件,對文件進行操作。
fd作為數組下標,fd的類型為int, < 0 為非法值, >=0 為合法值。在linux中,一個進程默認可以打開的文件數為1024個,fd的范圍為0~1023。可以通過設置,改變最大值。在linux中,值為0、1、2的fd,分別代表標准輸入、標准輸出、標准錯誤輸出。
- ll /proc/${PID}/fd | wc -l
- ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l)
就能知道進程打開的句柄數和線程數。
2. CPU 100% 問題定位
線上服務器中如果多實例部署,如何定位是哪個服務進程導致CPU過載,哪個線程導致CPU過載,那段代碼導致CPU過載?
大致步驟如下:
- 找到最耗CPU 的進程
- 找到最耗CPU 的線程
- 查看堆棧,定位線程在干嘛,定位對應代碼
2.1 找到最耗 CPU 的進程
使用 top 命令
- 執行 top -c 查看進程運行信息列表
- 輸入P(大寫) 進程按照CPU 使用率排序
好像top后就是按cpu使用率來排序的。
如上圖 最耗CPU的進程PID是7199
2.2 找到最耗 CPU 的線程
使用 top命令
- top -Hp 7199 顯示一個進程的線程運行信息
- 輸入大寫P ,線程按照CPU使用率排序
如上圖 進程 7199 中 最耗CPU的線程PID為7248
2.3 查看堆棧 定位對應代碼
- 將線程PID 轉化為16進制
使用 printf "%x\n" 7248
返回 1c50
- 參看堆棧,找到線程在干嘛
使用 jstack 7199 | grep '0x1c50' -C5 --color
- 打印進程堆棧
- 通過線程id 過濾得到線程堆棧
如上圖 耗CPU 最高的線程對應的線程名稱 "Thread-7" 以及相應的代碼 A.java
- 根據堆棧信息,找到相應的代碼
3. 其他方法
上面的方法比較原始,並且比較繁瑣,一般使用現有的輪子
-
arthas 快速高效
- 在使用 Arthas 之前,當遇到 Java 線上問題時,如 CPU 飆升、負載突高、內存溢出等問題,你需要查命令,查網絡,然后 jps、jstack、jmap、jhat、jstat、hprof 等一通操作。最終焦頭爛額,還不一定能查出問題所在。而現在,大多數的常見問題你都可以使用 Arthas 輕松定位,迅速解決,及時止損,准時下班。
- Arthas 是 Alibaba 在 2018 年 9 月開源的 Java 診斷工具。
-
show busy java thread 腳本
- 將上面的步驟進行腳本封裝,執行腳本直接得出結果,目前僅在linux上使用
- link
-
jmc
- jdk bin目錄下工具,可對應用進行監控