Linux系统监控命令个人总结之jstack查找高度占用CPU的java代码

来源:互联网 发布:淘宝旺铺专业版模板 编辑:程序博客网 时间:2024/05/19 23:02

ps命令

执行man ps,会列举出很多参数,我这里不一一讲解,就是选择性的讲解。

THREAD DISPLAY (线程显示)

参数 含义 H Show threads as if they were processes
查看所有存在的线程 -L Show threads, possibly with LWP and NLWP columns
显示线程,可能会显示LWP和NLWP列 -T Show threads, possibly with SPID column
显示线程,可能会显示SPID列 m Show threads after processes
查看一个进程起的线程数

PROCESS SELECTION BY LIST

参数 含义 p Select by process ID. Identical to -p and –pid.
显示指定的pid信息 -p Select by PID.
显示指定的pid信息 -f 完全格式化的清单。这个选项可以结合许多其他unix形式选项来添加额外的列

注意:-f:

does full-format listing. This option can be combined with many otherUNIX-style options to add additional columns. It also causes the command arguments to be printed. When used with -L, the NLWP (number of threads) and LWP (thread ID) columns will be added. See the c option, the format keyword args, and the format keyword comm.

有道翻译:

完全格式化的清单。这个选项可以结合许多其他unix形式选项来添加额外的列。它还会导致命令参数被打印出来。当使用-L,NLWP(数量的线程)LWP(线程ID)列将被添加。看到c选择,关键字参数的格式,格式字通讯。

找到最耗CPU的java进程

执行top命令

这里写图片描述

我们可以看出比较耗CPU的有:pid为13407和7957。
接下来我们再去找该进程中哪个线程耗CPU。

找到最耗CPU的java线程

ps -mp pid -o THREAD,tid,time #或者#ps -Lfp pid

执行ps -mp 7957 -o THREAD,tid

USER     %CPU PRI SCNT WCHAN  USER SYSTEM   TIDwebuser  85.6   -    - -         -      -     -webuser   0.0  19    - futex_    -      -  7987webuser   0.0  19    - futex_    -      -  7988webuser   0.0  19    - futex_    -      -  7989webuser   0.0  19    - futex_    -      -  7990webuser   0.0  19    - futex_    -      -  7991webuser  74.3  19    - -         -      -  7992webuser   0.5  19    - futex_    -      -  7993

可以看出是在id为7957的进程中id为7992的线程高度占用cpu

这个时候我们有两种方式来找到找到具体哪段代码有问题!

①纯敲命令:

我们先使用jstack命令把java堆栈信息打印到一个文件中。

jstack 7957 > test.txt

接着执行:

grep `printf "%x\n" 7992` test -A 30

打印结果是:

"DefaultQuartzScheduler_Worker-3" prio=10 tid=0x00007fcec053b000 nid=0x1f38 runnable [0x00007fceb018a000]   java.lang.Thread.State: RUNNABLE        at java.net.SocketInputStream.socketRead0(Native Method)        at java.net.SocketInputStream.read(SocketInputStream.java:152)        at java.net.SocketInputStream.read(SocketInputStream.java:122)        at java.net.SocketInputStream.read(SocketInputStream.java:108)        at redis.clients.util.RedisInputStream.fill(RedisInputStream.java:109)        at redis.clients.util.RedisInputStream.read(RedisInputStream.java:98)        at redis.clients.jedis.Protocol.processBulkReply(Protocol.java:97)        at redis.clients.jedis.Protocol.process(Protocol.java:72)        at redis.clients.jedis.Protocol.processMultiBulkReply(Protocol.java:122)        at redis.clients.jedis.Protocol.process(Protocol.java:68)        at redis.clients.jedis.Protocol.read(Protocol.java:131)        at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:199)        at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:192)        at redis.clients.jedis.Jedis.mget(Jedis.java:394)        at ggframework.bottom.hq.GGHQ.mget(GGHQ.java:683)        at ggframework.bottom.hq.GGHQ.mgetMap(GGHQ.java:609)        at ggframework.bottom.hq.GGHQ.listHangqing(GGHQ.java:128)        at ggjob.job.hq.push.HQComparator.getChangedHQ(HQComparator.java:64)        at ggjob.job.hq.push.HQComparator.getChangedHQ(HQComparator.java:34)        at ggjob.job.hq.push.PushSZHQTimeJob.doJob(PushSZHQTimeJob.java:88)        at ggjob.job.GGJob.execute(GGJob.java:107)        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)        - locked <0x000000060cd59dc0> (a java.lang.Object)

简单的解释下,jstack下这一串线程信息内容:
java代码
“DefaultQuartzScheduler_Worker-3” prio=10 tid=0x00007fcec053b000 nid=0x1f38 runnable [0x00007fceb018a000]

nid : 对应的linux操作系统下的tid,就是前面转化的16进制数字。
即 7992 转成16进制 为 1f38

tid: 这个应该是jvm的jmm内存规范中的唯一地址定位,如果你详细分析jvm的一些内存数据时用得上. 也就是我们要去分析jvm运行时数据区的内存分配情况,可以用上。

方法②:

我们先将7992转成16进制 1f38。(可以使用计数器,或者敲命令来转换)。
命令转换:

#printf "%x\n" pidprintf "%x\n" 7992

结果为 1f38

我们在使用jstack命令把java堆栈信息打印到一个文件中。

jstack 7957 > test.txt

再执行:

vim test.txt

打开文件,再输入/,再输入1f38,回车,就能定位到,我们要的信息。

结果:

"DefaultQuartzScheduler_Worker-3" prio=10 tid=0x00007fcec053b000 nid=0x1f38 runnable [0x00007fceb018b000]   java.lang.Thread.State: RUNNABLE        at java.net.SocketInputStream.socketRead0(Native Method)        at java.net.SocketInputStream.read(SocketInputStream.java:152)        at java.net.SocketInputStream.read(SocketInputStream.java:122)        at java.net.SocketInputStream.read(SocketInputStream.java:108)        at redis.clients.util.RedisInputStream.fill(RedisInputStream.java:109)        at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:45)        at redis.clients.jedis.Protocol.process(Protocol.java:64)        at redis.clients.jedis.Protocol.read(Protocol.java:131)        at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:162)        at redis.clients.jedis.Jedis.hmset(Jedis.java:716)        at ggjob.hqcache.GGHQCache.hset(GGHQCache.java:422)        at ggjob.hqcache.GGHQCache.cacheHQSnapshotChanged(GGHQCache.java:90)        at ggjob.job.hq.push.Messager.publishHQMessage(Messager.java:73)        at ggjob.job.hq.push.PushSZHQTimeJob.doJob(PushSZHQTimeJob.java:95)        at ggjob.job.GGJob.execute(GGJob.java:107)        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)

根据我公司的代码,可以看出是GGHQCache.java:422,接下来去GGHQCache.java的类中查找原因就可以啦。

jstack

英文描述:

jstack prints Java stack traces of Java threads for a given Java process or core file       or a remote debug server. For each Java frame, the  full  class  name,  method  name,       ’bci’  (byte  code  index)  and  line  number, if available, are printed. With the -m       option, jstack prints both Java and native frames of all threads along with the  ’pc’       (program  counter).  For  each  native  frame,  the closest native symbol to ’pc’, if       available, is printed. C++ mangled names are not demangled. To  demangle  C++  names,       the  output  of this command may be piped to c++filt. If the given process is running       on a 64-bit VM, you may need to specify the -J-d64 option, e.g.:       jstack -J-d64 -m pid

中文翻译:

jstack 为给指定java进程或者核心文件或者远程调试服务器打印java线程中的java堆栈信息。
对于每个java栈帧,如果有完整的类名,方法名,字节码的索引和行号的话,都会打印出来。
使用-m选项,jstack会把所有线程中java栈帧、native栈帧和程序计数器都打印出来。
对于每个native栈帧,如果在程序计数器中有最近的native符号,也会打印出来。

通过这段翻译我们可以知道jstack是专门用来打印java程序在jvm中堆栈信息的!

参考链接:
http://www.xitongzhijia.net/xtjc/20141203/31828.html

1 0