http://www.cnblogs.com/skyaccross/archive/2012/12/22/2829000.html
收到服務器報警,服務端的一個java服務佔用cpu200%多。該服務裏面跑了很多線程,於是想找到是誰引起的
1、首先dump出該進程的所有線程及狀態
使用命令 jstack PID 命令打印出CPU佔用過高進程的線程棧.
jstack -l 5683 > 5683.stack
將進程id爲5683的線程棧輸出到了文件
2、使用top命令找到耗cpu的線程
使用top -H -p PID 命令查看對應進程是哪個線程佔用CPU過高.
[goocar@LoginSVR ~]$ top -H -p 5683 top - 09:14:06 up 270 days, 18:33, 8 users, load average: 7.94, 9.70, 10.31 Tasks: 48 total, 2 running, 46 sleeping, 0 stopped, 0 zombie Cpu(s): 20.4% us, 30.5% sy, 0.0% ni, 43.8% id, 5.4% wa, 0.0% hi, 0.0% si Mem: 16625616k total, 16498560k used, 127056k free, 22020k buffers Swap: 16771820k total, 9362112k used, 7409708k free, 2224132k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 5728 ecar 16 0 2442m 1.3g 288m R 38.3 8.4 208:06.62 java 5726 ecar 16 0 2442m 1.3g 288m S 37.3 8.4 209:08.91 java 5727 ecar 16 0 2442m 1.3g 288m R 37.3 8.4 213:14.04 java 5729 ecar 16 0 2442m 1.3g 288m S 35.6 8.4 211:39.23 java 5683 ecar 16 0 2442m 1.3g 288m S 0.0 8.4 0:00.00 java 5685 ecar 18 0 2442m 1.3g 288m S 0.0 8.4 0:01.62 java 5686 ecar 16 0 2442m 1.3g 288m S 0.0 8.4 21:13.33 java
可以看到是 5726 ~ 5729這4個線程佔用的cpu比較高
3. 將線程的pid 轉成16進制,比如5729 = 0x1661
到第一步dump出來的 5683.stack 裏面找0x1661 就知道是哪個線程了
"Server-3" prio=10 tid=0x6f1fc000 nid=0x1661 runnable [0x6d67f000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.FileDispatcher.write0(Native Method) at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:29) at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:104) at sun.nio.ch.IOUtil.write(IOUtil.java:60) at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:334) - locked <0x77f3b3c0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:619)
經過查找,是服務線程比較忙,初步解決方法,就是加大服務線程數,重啓,問題解決。
線上遇到一個問題:
- <span style="font-size: medium;">Unable to open socket file: target process not responding or HotSpot VM not loaded
- The -F option can be used when the target process is not responding</span>
重啓後解決,主要原因是pid文件沒有生成,這裏記錄下相關的問題點。
首先解釋下 java.io.tmpdir
見 http://download.oracle.com/javase/1.4.2/docs/api/java/io/File.html
- <span style="font-size: x-small;"> <span style="font-size: medium;"> If the directory argument is null then the system-dependent default temporary-file directory will
- be used. The default temporary-file directory is specified by the system property java.io.tmpdir.
- On UNIX systems the default value of this property is typically "/tmp" or "/var/tmp";
- on Microsoft Windows systems it is typically "c:\\temp". A different value may be given to this
- system property when the Java virtual machine is invoked, but programmatic changes to this
- property are not guaranteed to have any effect upon the the temporary directory used by this
- method</span>
- </span>
其次看下jvmstat使用的前提
見 http://java.sun.com/performance/jvmstat/faq.html#3
- <span style="font-size: medium;">If the error message is of the form:
- Could not attach to vmid: reason
- The jvmstat tools can only monitor the HotSpot 1.4.1 JVM and only when the target JVM has been
- started with the -XX:+UsePerfData option. Please verify that your application is running with the
- correct JVM and that the required -XX option is set. </span>
- <span style="font-size: medium;">
- </span>
接着來說下上面2者的關係,jvmstat會生成一個目錄文件叫hsperfdata_username,那這個目錄文件在哪裏呢,默認的是生成在 java.io.tmpdir目錄下, java.io.tmpdir在linux下默認是/tmp下,故默認開啓了jvm monitor的功能以後就會在/tmp目錄下生成一個目錄叫 hsperfdata_username ,然後這個目錄中會有一個pid文件,可以利用strings查看裏面的文件內容,一般就是jvm的進程信息而已。
知道了這個所以我們可以自己修改這個目錄位置,防止被刪除而導致一些依賴這個目錄的程序出現問題。
Djava.io.tmpdir=/home/admin/xxxxxx
看下之前別人給sun的一個bug report與該問題相關的
JVM creates subdirectory "hsperfdata_xxx"
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5012932
temp dir locations should not be hardcoded for hsperfdata_<USER> dirctories
http://bugs.sun.com/view_bug.do?bug_id=6447182
針對jdk更新帶出的問題 ,參見一個blog說明
Java update breaks jps, jconsole, etc
http://underlap.blogspot.com/2011/03/java-update-breaks-jps-jconsole-etc.html
由此問題進一步引申開來就會發現以下幾點容易出問題的地方:
1:沒有生成 hsperfdata_xxx目錄報錯
2:生成 hsperfdata_xxx目錄但是沒有pid文件
3:沒權限生成,例如指定的/tmp或者其他目錄不可 寫,包括2種情況,一是沒權限,而是空間不夠
4:文件不可讀,例如2個不同的用戶來操作這個文件,一般是A用戶啓動java B用戶來運行jvmstat等等
5:java生成的目錄 和 jvmstat 使用的目錄文件不是同一個,這個可以見上面jdk update引起的bug導致