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很高,除了确实是计算密集型应用开发之外,通常原因都是出现了死循环。
(友情提示:本博文章欢迎转载,但请注明出处: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
最后打印线程的堆栈信息:
js tack 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、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)找到应用开发程序所在的进程号,命令如下
- 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,以二进制输出成文本。