下面通過模擬例項分析排查Java應用程式CPU和記憶體佔用過高的過程。如果是Java面試,這2個問題在面試過程中出現的概率很高,所以我打算在這裡好好總結一下。
1、Java CPU過高的問題排查
舉個例子,如下:
package com.classloading; public class Test { static class MyThread extends Thread { public void run() { // 死迴圈,消耗CPU int i = 0; while (true) { i++; } } } public static void main(String args[]) throws InterruptedException { new MyThread().start(); Thread.sleep(10000000); } }
使用top命令檢視佔用CPU過高的程式。如下圖所示。
檢視程式6102下執行緒的佔用情況,如下圖所示。
使用如下命令將6122轉換為16進製表示,如下:
匯出CPU佔用高程式的執行緒棧。命令如下:
jstack pid >> java.txt
內容如下:
mazhi@mazhi:~$ cat java.txt Attaching to remote server pid, please wait... 2021-02-23 15:38:18 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.192-b12 mixed mode): "Attach Listener" #10 daemon prio=9 os_prio=0 tid=0x00007f4ee0001000 nid=0x1956 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE // 這是0x17ea執行緒,也是佔用CPU最高的執行緒 "Thread-0" #9 prio=5 os_prio=0 tid=0x00007f4f180d6000 nid=0x17ea runnable [0x00007f4f044da000] java.lang.Thread.State: RUNNABLE at com.cpuhigh.Test$MyThread.run(Test.java:8) // 這裡指示第8行,則正是死迴圈的程式碼開始 ...
匯出的堆疊資訊有執行緒的狀態(一般要找RUNNABLE狀態)和呼叫堆疊結合來查詢問題。執行緒dump分析:執行緒dump分析主要目的是定位執行緒長時間停頓的原因
2、Java 記憶體過高的問題排查
舉個例子如下:
package com.classloading; import java.util.ArrayList; import java.util.List; public class Test { private static final int UNIT_MB = 1024 * 1024; public static void main(String args[]) throws InterruptedException{ List<Object> x = new ArrayList<Object>(); int i = 0; while(i<1000){ x.add(new byte[UNIT_MB]); i++; } Thread.sleep(1000000000); } }
通過jmap dump記憶體快照。如果是線上環境,注意dump之前必須先將流量切走,否則大記憶體dump是直接卡死服務。
命令列輸入:
jmap -histo <pid> | head -20
就可以檢視某個pid的java服務佔用記憶體排名前20的類,如下圖所示。
可以看到,佔用記憶體最多的是byte位元組陣列,共有1008個例項。
jmap
還有一個指令可以把整個記憶體情況轉成檔案形式儲存下來,如下:
jmap -dump:format=b,file=filename.bin <pid>
執行命令如下圖所示。
可以在JVM啟動時設定,如果發生OOM,則dump出檔案。命令如下:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof
如果快照檔案不大,可以下載到本地,然後通過MAT分析,也可以線上分析(https://fastthread.io/);如果快照檔案很大,可以在伺服器上直接分析,使用的命令是:
jhat dump.hprof
jhat也是jdk內建的工具之一。主要是用來分析java堆的命令,可以將堆中的物件以html的形式顯示出來,包括物件的數量,大小等等,並支援物件查詢語言。命令執行後如下圖所示。
訪問如下圖所示。
其中的Show heap histogram就會顯示物件佔用內在的大小。如下圖所示。