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 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===================