我正在使用检查 Linux 中的 Java 进程
top -H
但是,我无法读取“COMMAND”列中的线程名称(因为它太长了)。如果我使用 'c' 来扩展进程的全名,那么它仍然太长而无法适应。
如何获取命令的全名?
我正在使用检查 Linux 中的 Java 进程
top -H
但是,我无法读取“COMMAND”列中的线程名称(因为它太长了)。如果我使用 'c' 来扩展进程的全名,那么它仍然太长而无法适应。
如何获取命令的全名?
您可以使用该工具检查 java 线程jstack
。它将列出属于指定进程 pid 的所有线程的名称、堆栈跟踪和其他有用信息。
编辑: jstack 的线程转储中的参数 nid 是 LWP 的十六进制版本,由线程的 pid 列中的顶部显示。
这可能有点旧,但这是我将 top 和 jstack 合并在一起的方法。我使用了两个脚本,但我确信这一切都可以在一个脚本中完成。
首先,我将带有我的 java 线程的 pid 的 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 风格,并且可以在这里和那里进行一些调整。
我创建了一个类似 top 的命令,专门用于可视化按 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
安装。
With OpenJDK on Linux, JavaThread names don't propagate to native threads, you cannot see java thread name while inspecting native threads with any tool.
However there is some work in progress:
Personally, I find the OpenJDK development tool slow so I just apply patches myself.
就内核而言,线程没有名称。他们只有身份证号码。JVM 为线程分配名称,但这是进程内的私有内部数据,“顶级”程序无法访问(并且无论如何也不知道)。
这个 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}"
扩展Andre在 Perl 中的早期答案,这是 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)
老问题,但我也遇到了同样的问题top
。
事实证明,您可以简单地使用光标键将顶部的输出滚动到右侧:)
(但不幸的是,不会显示任何线程名称)
你提到了“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
输出故意非常简单,以使进一步处理(例如用于监视)更容易。