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

48 篇文章 0 订阅
45 篇文章 0 订阅

ps命令

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

THREAD DISPLAY (线程显示)

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

PROCESS SELECTION BY LIST

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

注意:-f:

does full-format listing. This option can be combined with many other
UNIX-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   TID
webuser  85.6   -    - -         -      -     -
webuser   0.0  19    - futex_    -      -  7987
webuser   0.0  19    - futex_    -      -  7988
webuser   0.0  19    - futex_    -      -  7989
webuser   0.0  19    - futex_    -      -  7990
webuser   0.0  19    - futex_    -      -  7991
webuser  74.3  19    - -         -      -  7992
webuser   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" pid
printf "%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

修改

=========2018年5月9日===============start===================

top -Hp pid
printf "%x" pid  -- 打印出的是十六进制
jstack pid | grep 十六进制 -C11 --color

这个更容易记些吧!
=========2018年5月9日===============end===================

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值