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,以二进制输出成文本。

posted on 2020-03-12 18:50  四海骄阳  阅读(2223)  评论(0编辑  收藏  举报

导航