
1,使用指令top -p <pid> ,顯示你的Java程序的記憶體情況,pid是你的java程序号,比如4977
2,按H,擷取每個線程的記憶體情況
3,找到記憶體和cpu占用最高的線程pid,比如4977
4,執行 System.out.println(Integer.toHexString(4977));8 得到 0x1371 ,此為線程id的十六進制
5,執行 jstack 4977|grep -A 10 1371,得到線程堆棧資訊中1371這個線程所在行的後面10行
6,檢視對應的堆棧資訊找出可能存在問題的代碼
轉載自:
http://www.cnblogs.com/E-star/p/5314529.html

1,使用指令top -p <pid> ,顯示你的Java程序的記憶體情況,pid是你的java程序号,比如4977
2,按H,擷取每個線程的記憶體情況
3,找到記憶體和cpu占用最高的線程pid,比如4977
4,執行 System.out.println(Integer.toHexString(4977));8 得到 0x1371 ,此為線程id的十六進制
5,執行 jstack 4977|grep -A 10 1371,得到線程堆棧資訊中1371這個線程所在行的後面10行
6,檢視對應的堆棧資訊找出可能存在問題的代碼
一個應用占用CPU很高,除了确實是計算密集型應用之外,通常原因都是出現了死循環。
(友情提示:本博文章歡迎轉載,但請注明出處:hankchen,http://www.blogjava.net/hankchen)
以我們最近出現的一個實際故障為例,介紹怎麼定位和解決這類問題。
根據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指令。可以檢視某個程序的目前線程棧運作情況。
轉載:hankchen,http://www.blogjava.net/hankchen)

1,使用指令top -p <pid> ,顯示你的Java程序的記憶體情況,pid是你的java程序号,比如4977
2,按H,擷取每個線程的記憶體情況
3,找到記憶體和cpu占用最高的線程pid,比如4977
4,執行 System.out.println(Integer.toHexString(4977));8 得到 0x1371 ,此為線程id的十六進制
5,執行 jstack 4977|grep -A 10 1371,得到線程堆棧資訊中1371這個線程所在行的後面10行
6,檢視對應的堆棧資訊找出可能存在問題的代碼