我正在使用
检查Linux中的Java进程top -H
但是,我无法读取“COMMAND”列中的线程名称(因为它太长)。如果我使用'c'来扩展该过程的全名,那么它仍然很长。
如何获取命令的全名?
答案 0 :(得分:24)
您可以使用工具jstack
检查Java线程。它将列出属于指定进程pid的所有线程的名称,堆栈跟踪和其他有用信息。
编辑:jstack的线程转储中的参数nid是LWP的十六进制版本,它在线程的pid列中由顶部显示。
答案 1 :(得分:24)
这可能有点老了,但这就是我所做的有点将top和jstack合并在一起。我使用了两个脚本,但我确信这一切都可以在一个脚本中完成。
首先,我使用我的java线程的pids将top的输出保存到文件中,并将jstack输出保存到另一个文件中:
#!/bin/sh
top -H -b -n 1 | grep java > /tmp/top.log
jstack -l `ps fax | grep java | grep tomcat | sed "s/ *\([0-9]*\) .*/\1/g"` > /tmp/jstack.log
然后我使用perl脚本调用bash脚本(这里称为cpu-java.sh)并将两个文件合并(/tmp/top.log和/tmp/jstack.log):
#!/usr/bin/perl
system("sh cpu-java.sh");
open LOG, "/tmp/top.log" or die $!;
print "PID\tCPU\tMem\tJStack Info\n";
while ($l = <LOG>) {
$pid = $l;
$pid =~ s/root.*//g;
$pid =~ s/ *//g;
$hex_pid = sprintf("%#x", $pid);
@values = split(/\s{2,}/, $l);
$pct = $values[4];
$mem = $values[5];
open JSTACK, "/tmp/jstack.log" or die $!;
while ($j = <JSTACK>){
if ($j =~ /.*nid=.*/){
if ($j =~ /.*$hex_pid.*/){
$j =~ s/\n//;
$pid =~ s/\n//;
print $pid . "\t" . $pct . "\t" . $mem . "\t" . $j . "\n";
}
}
}
close JSTACK;
}
close LOG;
输出帮助我找出哪些线程正在占用我的cpu:
PID CPU Mem JStack Info
22460 0 8.0 "main" prio=10 tid=0x083cb800 nid=0x57bc runnable [0xb6acc000]
22461 0 8.0 "GC task thread#0 (ParallelGC)" prio=10 tid=0x083d2c00 nid=0x57bd runnable
22462 0 8.0 "GC task thread#1 (ParallelGC)" prio=10 tid=0x083d4000 nid=0x57be runnable
22463 0 8.0 "GC task thread#2 (ParallelGC)" prio=10 tid=0x083d5800 nid=0x57bf runnable
22464 0 8.0 "GC task thread#3 (ParallelGC)" prio=10 tid=0x083d7000 nid=0x57c0 runnable
...
然后我可以回到/tmp/jstack.log并查看有问题的线程的堆栈跟踪,并尝试找出从那里发生的事情。当然这个解决方案依赖于平台,但它应该适用于* nix的大多数版本以及一些调整。
答案 2 :(得分:14)
我创建了一个类似顶级的命令,专门用于可视化按CPU使用率排序的Java线程,并将源代码发布在:https://github.com/jasta/jprocps。命令行语法并不像top那样丰富,但它确实支持一些相同的命令:
$ jtop -n 1
示例输出(显示ant和IntelliJ运行):
PID TID USER %CPU %MEM THREAD
13480 13483 jasta 104 2.3 main
13480 13497 jasta 86.3 2.3 C2 CompilerThread1
13480 13496 jasta 83.0 2.3 C2 CompilerThread0
4866 4953 jasta 1.0 13.4 AWT-EventQueue-1 12.1.4#IC-129.713, eap:false
4866 14154 jasta 0.9 13.4 ApplicationImpl pooled thread 36
4866 5219 jasta 0.8 13.4 JobScheduler pool 5/8
从这个输出中,我可以手动提取jconsole
或jstack
中的线程堆栈跟踪,并找出发生了什么。
注意: jtop
是用Python编写的,需要安装jstack
。
答案 3 :(得分:4)
就内核而言,线程没有名称;他们只有身份证号码。 JVM为线程分配名称,但这是进程中的私有内部数据,“顶级”程序无法访问(并且无论如何都不知道)。
答案 4 :(得分:3)
从JDK 8开始我发现jstack is outdated。我用来检索所有Java Thread名称的是:
<JDK_HOME>/bin/jcmd <PID> Thread.print
查看jcmd documentation了解更多信息。
答案 5 :(得分:2)
在Linux上使用OpenJDK时,JavaThread名称不会传播到native threads,在使用任何工具检查本机线程时都看不到java线程名称。
然而,有一些工作正在进行中:
就个人而言,我发现OpenJDK开发工具很慢,所以我只是自己应用补丁。
答案 6 :(得分:1)
此shell脚本将jstack和top的输出结合起来,按CPU使用情况列出Java线程。它需要一个参数,即拥有进程的帐户用户。
名称: jstack-top.sh
#!/bin/sh
#
# jstack-top - join jstack and top to show cpu usage, etc.
#
# Usage: jstack-top <user> | view -
#
USER=$1
TOPS="/tmp/jstack-top-1.log"
JSKS="/tmp/jstack-top-2.log"
PIDS="$(ps -u ${USER} --no-headers -o pid:1,cmd:1 | grep 'bin/java' | grep -v 'grep' | cut -d' ' -f1)"
if [ -f ${JSKS} ]; then
rm ${JSKS}
fi
for PID in ${PIDS}; do
jstack -l ${PID} | grep "nid=" >>${JSKS}
done
top -u ${USER} -H -b -n 1 | grep "%CPU\|java" | sed -e 's/[[:space:]]*$//' > ${TOPS}
while IFS= read -r TOP; do
NID=$(echo "${TOP}" | sed -e 's/^[[:space:]]*//' | cut -d' ' -f1)
if [ "${NID}" = "PID" ]; then
JSK=""
TOP="${TOP} JSTACK"
else
NID=$(printf 'nid=0x%x' ${NID})
JSK=$(grep "${NID} " ${JSKS})
fi
echo "${TOP} ${JSK}"
done < "${TOPS}"
答案 7 :(得分:0)
旧问题,但top
我遇到了同样的问题。
事实证明,只需使用光标键即可滚动顶部的输出:)
(但不幸的是,不会显示任何线程名称)
答案 8 :(得分:0)
您提到了“ Linux”。然后使用小工具“ threadcpu”可能是一种解决方案:
threadcpu_-_show_cpu_usage_of_threads
$ threadcpu -h
threadcpu shows CPU usage of threads in user% and system%
usage:
threadcpu [-h] [-s seconds] [-p path-to-jstack]
options:
-h display this help page
-s measuring interval in seconds, default: 10
-p path to JRE jstack, default: /usr/bin/jstack
example usage:
threadcpu -s 30 -p /opt/java/bin/jstack 2>/dev/null|sort -n|tail -n 12
output columns:
user percent <SPACE> system percent <SPACE> PID/NID [ <SPACE> JVM thread name OR (process name) ]
一些示例输出:
$ threadcpu |sort -n|tail -n 8
3 0 33113 (klzagent)
3 0 38518 (klzagent)
3 0 9874 (BESClient)
3 41 6809 (threadcpu)
3 8 27353 VM Periodic Task Thread
6 0 31913 hybrisHTTP4
21 8 27347 C2 CompilerThread0
50 41 3244 (BESClient)
$ threadcpu |sort -n|tail -n 8
0 20 52358 (threadcpu)
0 40 32 (kswapd0)
2 50 2863 (BESClient)
11 0 31861 Gang worker#0 (Parallel CMS Threads)
11 0 31862 Gang worker#1 (Parallel CMS Threads)
11 0 31863 Gang worker#2 (Parallel CMS Threads)
11 0 31864 Gang worker#3 (Parallel CMS Threads)
47 10 31865 Concurrent Mark-Sweep GC Thread
$ threadcpu |sort -n|tail -n 8
2 0 14311 hybrisHTTP33
2 4 60077 ajp-bio-8009-exec-11609
2 8 30657 (klzagent)
4 0 5661 ajp-bio-8009-exec-11649
11 16 28144 (batchman)
15 20 3485 (BESClient)
21 0 7652 ajp-bio-8009-exec-11655
25 0 7611 ajp-bio-8009-exec-11654
故意使输出非常简单,以使进一步处理(例如监视)更加容易。
答案 9 :(得分:0)
在Perl中扩展了Andre's的较早答案,以下是Python中运行速度更快的答案。
它重新使用先前创建的文件,并且不会在jstack输出上循环几次:
#!/usr/bin/env python
import re
import sys
import os.path
import subprocess
# Check if jstack.log top.log files are present
if not os.path.exists("jstack.log") or not os.path.exists("top.log"):
# Delete either file
os.remove("jstack.log") if os.path.exists("jstack.log") else None
os.remove("top.log") if os.path.exists("top.log") else None
# And dump them via a bash run
cmd = """
pid=$(ps -e | grep java | sed 's/^[ ]*//g' | cut -d ' ' -f 1)
top -H -b -n 1 | grep java > top.log
/usr/intel/pkgs/java/1.8.0.141/bin/jstack -l $pid > jstack.log
"""
subprocess.call(["bash", "-c", cmd])
# Verify that both files were written
for f in ["jstack.log", "top.log"]:
if not os.path.exists(f):
print "ERROR: Failed to create file %s" % f
sys.exit(1)
# Thread ID parser
jsReg = re.compile('"([^\"]*)".*nid=(0x[0-9a-f]*)')
# Top line parser
topReg = re.compile('^\s*([0-9]*)(\s+[^\s]*){7}\s+([0-9]+)')
# Scan the entire jstack file for matches and put them into a dict
nids = {}
with open("jstack.log", "r") as jstack:
matches = (jsReg.search(l) for l in jstack if "nid=0x" in l)
for m in matches:
nids[m.group(2)] = m.group(1)
# Print header
print "PID\tNID\tCPU\tTHREAD"
# Scan the top output and emit the matches
with open("top.log", "r") as top:
matches = (topReg.search(l) for l in top)
for m in matches:
# Grab the pid, convert to hex and fetch from NIDS
pid = int(m.group(1))
nid = "0x%x" % pid
tname = nids.get(nid, "<MISSING THREAD>")
# Grab CPU percent
pct = int(m.group(3))
# Emit line
print "%d\t%s\t%d\t%s" % (pid, nid, pct, tname)