ps -mp pid -o THREAD,tid,time;printf "%x\n" tid;js


http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/57422.shtml

 

原文內容:

線上 應用開發故障排查之一:高cpu占用

一個應用開發占用cpu很高,除了確實是計算密集型應用開發之外,通常原因都是出現了死循環。

(友情提示:本博文章歡迎轉載,但請注明出處:hankchen,http://www.blogjava.net/hankchen

以我們最近出現的一個實際故障為例,介紹怎么定位和解決這類問題。

clip_image002

根據top命令,發現pid為28555的java進程占用cpu高達200%,出現故障。

通過ps aux | grep pid命令,可以進一步確定是tomcat進程出現了問題。但是,怎么定位到具體線程或者代碼呢?

首先顯示線程列表:

ps -mp pid -o thread,tid,time

1

找到了耗時最高的線程28802,占用cpu時間快兩個小時了!

其次將需要的線程id轉換為16進制格式:

printf "%x\n" tid

2

最后打印線程的堆棧信息:

js tack pid |grep tid -a 30

3

找到出現問題的代碼了!

現在來分析下具體的代碼: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、js tack:java提供的命令。可以查看某個進程的當前線程棧運行情況。根據這個命令的輸出可以定位某個進程的所有線程的當前運行狀態、運行代碼,以及是否死鎖等等。

4、pstack:linux命令。可以查看某個進程的當前線程棧運行情況。

(友情提示:本博文章歡迎轉載,但請注明出處:hankchen,http://www.blogjava.net/hankchen

 

 

 

 

http://binma85.馬開東/blog/778986

 

開門見山,本文將簡述如何使用java thread dump來分析cpu高使用率以及線程死鎖問題。 
一般java thread dump用於web開發中分析web容器或是應用開發服務器開發的性能問題還是比較常用並有效的。常用

 

此文來自: 馬開東博客 轉載請注明出處 網址:

的入門級web容器tomcat,以及高級別的jboss、websphere、weblogic等的性能調優問題都可以使用java thread dump來分析。 
首先,闡述一下thread dump常用來解決的是何種問題 
(1)高cpu使用 
(2)線程死鎖 
其次,使用步驟[以jboss為例] 
1..get thread dump log 
(1)找到應用開發程序所在的進程號,命令如下 

 

java代碼     收藏代碼
  1. ps aux |grep 'jboss' | grep 'java'  

、 
獲取需要的pid 
(2)執行sudo kill -3 pid獲取thread dump log(pid是第一步獲取)。 
注意:在不同的linux環境下執行輸出的日志的地方可能不同。在ibm的powerpc小型機上的linux上執行kill -3 pid會在工作目錄下產生類似javacore.20100409.161739.7614.0001.txt的文件。jboss默認環境下,thread dump log輸出到jboss console,所以thread dump信息會輸出到個人定義的控制台打印log中。 
部分示例如下所以: 

引用

2010-10-08 20:27:42 
full thread dump java hotspot(tm) server vm (16.3-b01 mixed mode): 

"http-182.50.0.138-8084-6" daemon prio=10 tid=0x08ce5000 nid=0x6a4c in object.wait() [0x87b5c000] 
   java.lang.thread.state: waiting (on object monitor) 
at java.lang.object.wait(native method) 
- waiting on <0x95eb81b0> (a org.apache.tomcat.util.net.jioendpoint$worker) 
at java.lang.object.wait(object.java:485) 
at org.apache.tomcat.util.net.jioendpoint$worker.await(jioendpoint.java:415) 
- locked <0x95eb81b0> (a org.apache.tomcat.util.net.jioendpoint$worker) 
at org.apache.tomcat.util.net.jioendpoint$worker.run(jioendpoint.java:441) 
at java.lang.thread.run(thread.java:619) 

"http-182.50.0.138-8084-5" daemon prio=10 tid=0x08c2e000 nid=0x6a4b in object.wait() [0x87bad000] 
   java.lang.thread.state: waiting (on object monitor) 
at java.lang.object.wait(native method) 
- waiting on <0x95ed0600> (a org.apache.tomcat.util.net.jioendpoint$worker) 
at java.lang.object.wait(object.java:485) 
at org.apache.tomcat.util.net.jioendpoint$worker.await(jioendpoint.java:415) 
- locked <0x95ed0600> (a org.apache.tomcat.util.net.jioendpoint$worker) 
at org.apache.tomcat.util.net.jioendpoint$worker.run(jioendpoint.java:441) 
at java.lang.thread.run(thread.java:619) 

"ajp-127.0.0.1-8009-acceptor-0" daemon prio=10 tid=0x894de800 nid=0x6a45 runnable [0x881f3000] 
   java.lang.thread.state: runnable 
at java.net.plainsocketimpl.socketaccept(native method) 
at java.net.plainsocketimpl.accept(plainsocketimpl.java:390) 
- locked <0x949c1288> (a java.net.sockssocketimpl) 
at java.net.serversocket.implaccept(serversocket.java:453) 
at java.net.serversocket.accept(serversocket.java:421) 
at org.apache.tomcat.util.net.defaultserversocketfactory.acceptsocket(defaultserversocketfactory.java:61)
at org.apache.tomcat.util.net.jioendpoint$acceptor.run(jioendpoint.java:309) 
at java.lang.thread.run(thread.java:619) 

defaultquartzscheduler_quartzschedulerthread" prio=10 tid=0x8a460800 nid=0x6a38 sleeping[0x88818000] 
   java.lang.thread.state: timed_waiting (sleeping) 
at java.lang.thread.sleep(native method) 
at org.quartz.core.quartzschedulerthread.run(quartzschedulerthread.java:394) 



(3)獲取線程信息 
使用上面的ps或者使用top命令也可以。獲取的線程信息如下所示: 

引用

27143 root      20   0  780m 376m  11m s   17 11.5   2:56.48 java                                                                   
4839 root      20   0  778m 162m  11m s   10  5.0   1717:03 java                                                                   
5049 root      20   0  764m 147m  11m s    4  4.5   1744:06 java                                                                   
    1 root      20   0  2100  720  624 s    0  0.0   0:28.08 init                                                                   
    2 root      15  -5     0    0    0 s    0  0.0   0:00.00 kthreadd                                                               
    3 root      rt  -5     0    0    0 s    0  0.0   0:00.44 migration/0   


第一列是十進制pid,需要轉化為16進制后才能和thread dump信息對應。 
2.分析thread dump信息[不在列舉示例,只講思想] 
(1)分析高cpu使用線程的thread dump信息,查找那些代碼導致高cpu使用。 
(2)線程死鎖 
    a.為了發現線程動態變化,需要多次做thread dump,每次間隔10-30s為佳. 
    b.線程狀態用 runnable(正在運行)、waiting for monitor(主動等待)、waiting for monitor entry(死鎖)。所以我們最多的是關注runnable和entry類型的線程。 
一種典型的死鎖是在server端多個應用開發同時使用同一個jboss資源,這時候需要將多個應用開發分不到不用的隊列中。

 

 

 

 

 

 

 

http://javag.馬開東/blog/718243

 

 

參考文獻:

http://www.51testing.com/?uid-188107-action-viewspace-itemid-226468

1.分析內存的開發工具

eclipse memory analyzer tool(俗稱mat),下載地址為: http://www.eclipse.org/mat/

使用memory analyzer tool(mat)分析內存泄漏(一)

使用memory analyzer tool(mat)分析內存泄漏(二)    使用前需要在linux上通過jmap -dump:format=b,file={$filename} ${pid}方式將heap的內存快照文件給dump出來,然后就可以通過上面的mat進行分析了。注意dump出來的文件名要以bin作為后

 

此文來自: 馬開東博客 轉載請注明出處 網址:

綴名不然可能識別不了哦.

 

例如: jmap -dump:format=b,file=a.bin 2298

 

2.線程狀態分析

"exec-613" id=713 in blocked on lock=com.ss.nio.clientfactory@2262ce5f owned by tomcatthreadpool-exec-553 id=623

 

"exec-553" id=623 in timed_waiting on lock=com.ss.nio.abstractrequest@35ce75e at java.lang.object.wait(native method)

"nioprocessor-1" id=700 in runnable (running in native) at sun.nio.ch.epollarraywrapper.epollwait(native method) at sun.nio.ch.epollarraywrapper.poll(epollarraywrapper.java:215) at sun.nio.ch.epollselectorimpl.doselect(epollselectorimpl.java:65) at sun.nio.ch.selectorimpl.lockanddoselect(selectorimpl.java:69) at sun.nio.ch.selectorimpl.select(selectorimpl.java:80)

"rmi tcp connection(8)-172.25.3.81" id=698 in runnable at sun.management.threadimpl.getthreadinfo0(native method) at sun.management.threadimpl.getthreadinfo(threadimpl.java:145) at sun.reflect.nativemethodaccessorimpl.invoke0(native method) at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39) at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25) at java.lang.reflect.method.invoke(method.java:597)

 

 

runnable(正在運行的,消耗cpu)  timed_waiting(等待被分配到cpu運行的,現在不消耗cpu) blocked(被阻塞,在阻塞解除前不能被分配cpu執行,現在不消耗cpu)

 

exec-613占用了鎖,exec-553需要的鎖被exec-613占用無法執行處於blocked狀態.

nioprocessor-1正在運行,並且他的開發方法 在調用native開發方法 .

rmi tcp connection(8)-172.25.3.81正在運行.

 

(一) jinfo   jinfo打印一個給定的java進程或核心文件或一個遠程調試服務器開發的java配置信息。配置信息包括java系統開發屬性和jvm命令行標志(更多信息,請參考《jinfo-configuration info》)。   (二) jmap   jmap:如果這個開發工具不使用任何選項(除了pid或core選項)運行,那么它顯示類似於solaris的pmap開發工具所輸出的信息。這個開發工具支持針對java堆可觀察性的若干其它選項。   在java se 6平台中,新加入了一個-dump選項。這樣可以使jmap能夠把java堆信息復制到一個文件中,然后我們可以使用新的jhat命令(見下面一節)來分析它。   jmap -dump選項並不使用solaris libproc來實現實時處理;而是,它運行當前正運行的jvm中的一小段代碼,由此來實現堆復制。既然這種堆復制代碼運行於jvm內部,那么其速度是比較快的。堆復制的效果大致相當於實現一次"完全的gc"(對整個堆的垃圾收集),再加上把該堆的內容寫入到文件中。實現堆復制的另外一種可能的思路是使用 gcore來進行核心復制並且運行"jmap -dump"(這與以"離線"方式運行的核心復制形成對照)。 

 

    可以輸出某個java進程內存內對象的情況,甚至可以將vm 中的heap,以二進制輸出成文本。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM