J'inspecte un processus Java sous Linux en utilisant
top -H
Cependant, je ne peux pas lire le nom du fil dans la colonne "COMMAND" (car il est trop long). Si j'utilise 'c' pour développer le nom complet du processus, alors il est encore trop long pour l'adapter.
Comment puis-je obtenir le nom complet de la commande?
C’est peut-être un peu vieux, mais voici ce que j’ai fait pour fusionner un peu haut et jstack ensemble. J'ai utilisé deux scripts, mais je suis sûr que tout pourrait être fait en un.
Premièrement, j'enregistre la sortie de top avec les pids de mes threads Java dans un fichier et enregistre la sortie de jstack dans un autre fichier:
#!/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
Ensuite, j'utilise un script Perl pour appeler le script bash (appelé ici cpu-Java.sh) et un peu fusionner les deux fichiers (/tmp/top.log et /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;
La sortie m'aide à savoir quels threads monopolisent mon processeur:
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
...
Ensuite, je peux revenir à /tmp/jstack.log et jeter un coup d'œil à la trace de pile pour le thread problématique et essayer de comprendre ce qui se passe à partir de là. Bien sûr, cette solution dépend de la plate-forme, mais elle devrait fonctionner avec la plupart des versions de * nix et quelques modifications apportées ici et là.
Vous pouvez inspecter les threads Java avec l'outil jstack
. Il listera les noms, stacktraces et autres informations utiles de tous les threads appartenant au pid de processus spécifié.
Edit : Le paramètre nid dans le thread dump de jstack est la version hexadécimale du LWP affichée en haut dans la colonne pid des threads.
J'ai créé une commande de type top spécifiquement pour visualiser les threads Java classés en fonction de l'utilisation du processeur et posté le code source à l'adresse: https://github.com/jasta/jprocps . La syntaxe de la ligne de commande n’est pas aussi riche que celle de top, mais elle prend en charge certaines des mêmes commandes:
$ jtop -n 1
Exemple de sortie (montrant ant et IntelliJ en cours d'exécution):
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
À partir de cette sortie, je peux extraire manuellement la trace de pile du thread dans jconsole
ou jstack
et comprendre ce qui se passe.
NOTE:jtop
est écrit en Python et nécessite que jstack
soit installé.
Les threads n'ont pas de noms en ce qui concerne le noyau; ils ont seulement des numéros d'identification. La JVM attribue des noms aux threads, mais il s’agit de données internes privées au sein du processus, auxquelles le programme "top" ne peut pas accéder (et n’a pas connaissance de toute façon).
Pour autant que j'ai découvert jstack est obsolète à partir de JDK 8. Ce que j'ai utilisé pour récupérer tous les noms de threads Java est:
<JDK_HOME>/bin/jcmd <PID> Thread.print
Vérifiez documentation jcmd pour plus.
Avec OpenJDK sous Linux, JavaThread noms ne se propagent pas vers threads natifs , vous ne pouvez pas voir le nom du thread Java lors de l'inspection des threads natifs avec un outil.
Cependant, des travaux sont en cours:
Personnellement, je trouve l'outil de développement OpenJDK lent, aussi je n'applique que moi-même les correctifs.
Ce script shell combine les résultats de jstack et top pour répertorier les threads Java en fonction de l'utilisation du processeur. Il attend un argument, l'utilisateur du compte qui possède les processus.
Nom: 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}"
Vieille question, mais j'avais exactement le même problème avec top
.
En fin de compte, vous pouvez faire défiler la sortie du haut vers la droite en utilisant simplement les touches des curseurs :)
(mais malheureusement, il n'y aura pas de fil name montré)
En développant Andre's plus tôt en Perl, en voici un en Python qui tourne beaucoup plus vite.
Il réutilise les fichiers créés précédemment et ne boucle pas plusieurs fois sur la sortie 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)
Vous avez parlé de "Linux". Ensuite, utiliser le petit outil "threadcpu" pourrait être une solution:
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) ]
Quelques exemples de sorties:
$ 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
La sortie est intentionnellement très simple pour faciliter le traitement ultérieur (par exemple, pour la surveillance).