Java中的CPU佔用高和記憶體佔用高的問題排查

歸去來兮辭發表於2021-02-23

下面通過模擬例項分析排查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就會顯示物件佔用內在的大小。如下圖所示。 

 

 

 

  

 

 

相關文章