Java線上應用故障排查之一:高CPU佔用【轉】
近期java應用,CPU使用率一直很高,經常達到100%,通過以下步驟完美解決,分享一下。
方法一:
轉載:http://www.linuxhot.com/java-cpu-used-high.html
1.jps 獲取Java程序的PID。
2.jstack pid >> java.txt 匯出CPU佔用高程序的執行緒棧。
3.top -H -p PID 檢視對應程序的哪個執行緒佔用CPU過高。
4.echo “obase=16; PID” | bc 將執行緒的PID轉換為16進位制,大寫轉換為小寫。
5.在第二步匯出的Java.txt中查詢轉換成為16進位制的執行緒PID。找到對應的執行緒棧。
6.分析負載高的執行緒棧都是什麼業務操作。優化程式並處理問題。
方法二:
1.使用top 定位到佔用CPU高的程序PID
top
通過ps aux | grep PID命令
2.獲取執行緒資訊,並找到佔用CPU高的執行緒
ps -mp pid -o THREAD,tid,time | sort -rn
3.將需要的執行緒ID轉換為16進位制格式
printf "%x\n" tid
4.列印執行緒的堆疊資訊
jstack pid |grep tid -A 30
一個應用佔用CPU很高,除了確實是計算密集型應用之外,通常原因都是出現了死迴圈。
以我們最近出現的一個實際故障為例,介紹怎麼定位和解決這類問題。
根據top命令,發現PID為28555的Java程序佔用CPU高達200%,出現故障。
通過ps aux | grep PID命令,可以進一步確定是tomcat程序出現了問題。但是,怎麼定位到具體執行緒或者程式碼呢?
首先顯示執行緒列表:
ps -mp pid -o THREAD,tid,time
找到了耗時最高的執行緒28802,佔用CPU時間快兩個小時了!
其次將需要的執行緒ID轉換為16進位制格式:
printf "%x\n" tid
最後列印執行緒的堆疊資訊:
jstack pid |grep tid -A 30
找到出現問題的程式碼了!
現在來分析下具體的程式碼:ShortSocketIO.readBytes(ShortSocketIO.java:106)
ShortSocketIO是應用封裝的一個用短連線Socket通訊的工具類。readBytes函式的程式碼如下:
public byte[] readBytes(int length) throws IOException {
if ((this.socket == null) || (!this.socket.isConnected())) {
throw new IOException("++++ attempting to read from closed socket");
}
byte[] result = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
if (this.recIndex >= length) {
bos.write(this.recBuf, 0, length);
byte[] newBuf = new byte[this.recBufSize];
if (this.recIndex > length) {
System.arraycopy(this.recBuf, length, newBuf, 0, this.recIndex - length);
}
this.recBuf = newBuf;
this.recIndex -= length;
} else {
int totalread = length;
if (this.recIndex > 0) {
totalread -= this.recIndex;
bos.write(this.recBuf, 0, this.recIndex);
this.recBuf = new byte[this.recBufSize];
this.recIndex = 0;
}
int readCount = 0;
while (totalread > 0) {
if ((readCount = this.in.read(this.recBuf)) > 0) {
if (totalread > readCount) {
bos.write(this.recBuf, 0, readCount);
this.recBuf = new byte[this.recBufSize];
this.recIndex = 0;
} else {
bos.write(this.recBuf, 0, totalread);
byte[] newBuf = new byte[this.recBufSize];
System.arraycopy(this.recBuf, totalread, newBuf, 0, readCount - totalread);
this.recBuf = newBuf;
this.recIndex = (readCount - totalread);
}
totalread -= readCount;
}
}
}
問題就出在標紅的程式碼部分。如果this.in.read()返回的資料小於等於0時,迴圈就一直進行下去了。而這種情況在網路擁塞的時候是可能發生的。
至於具體怎麼修改就看業務邏輯應該怎麼對待這種特殊情況了。
最後,總結下排查CPU故障的方法和技巧有哪些:
1、top命令:Linux命令。可以檢視實時的CPU使用情況。也可以檢視最近一段時間的CPU使用情況。
2、PS命令:linux命令。強大的程序狀態監控命令。可以檢視程序以及程序中執行緒的當前CPU使用情況。屬於當前狀態的取樣資料。
3、jstack:Java提供的命令。可以檢視某個程序的當前執行緒棧執行情況。根據這個命令的輸出可以定位某個程序的所有執行緒的當前執行狀態、執行程式碼,以及是否死鎖等等。
4、pstack:Linux命令。可以檢視某個程序的當前執行緒棧執行情況。
轉自
http://blog.csdn.net/blade2001/article/details/9065985