wake-up-neo.com

Java-Threads unter Linux mit top überprüfen

Ich überprüfe einen Java-Prozess in Linux mit

top -H

Ich kann jedoch nicht den Namen des Threads in der Spalte "BEFEHL" lesen (weil er zu lang ist). Wenn ich 'c' verwende, um den vollständigen Namen des Prozesses zu erweitern, ist es noch zu lang, um zu passen.

Wie erhalte ich den vollständigen Namen des Befehls?

33
Jake

Dies mag ein wenig alt sein, aber ich habe etwas getan, um top zusammenzubringen und zusammen zu stapeln. Ich habe zwei Skripte verwendet, aber ich bin sicher, dass alles in einem erledigt werden kann.

Zuerst speichere ich die Ausgabe von top mit den pids für meine Java-Threads in einer Datei und speichere die Jstack-Ausgabe in einer anderen Datei:

#!/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

Dann benutze ich ein Perl-Skript, um das Bash-Skript (hier cpu-Java.sh genannt) aufzurufen und die beiden Dateien (/tmp/top.log und /tmp/jstack.log) zusammenzuführen:

#!/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;

Die Ausgabe hilft mir herauszufinden, welche Threads meine CPU belasten:

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

Dann kann ich zurück nach /tmp/jstack.log gehen und mir den Stack-Trace für den problematischen Thread ansehen und versuchen, herauszufinden, was von dort aus los ist. Natürlich ist diese Lösung plattformabhängig, sollte aber mit den meisten * nix-Geschmacksrichtungen funktionieren und hier und da einige Optimierungen vornehmen.

23
Andre

Sie können Java-Threads mit dem Tool jstack überprüfen. Es werden die Namen, Stacktraces und andere nützliche Informationen aller Threads aufgelistet, die zu der angegebenen Prozess-PID gehören.

Edit : Der Parameter nid im Thread-Dump von jstack ist die Hex-Version des LWP, die von top in der pid-Spalte für Threads angezeigt wird.

23

Ich habe einen topartigen Befehl speziell für die Visualisierung von Java-Threads erstellt, die nach CPU-Nutzung geordnet sind, und den Quellcode unter folgendem Link veröffentlicht: https://github.com/jasta/jprocps . Die Befehlszeilensyntax ist bei weitem nicht so reich wie top, unterstützt jedoch einige der gleichen Befehle:

$ jtop -n 1

Beispielausgabe (zeigt ant und 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

Von dieser Ausgabe aus kann ich die Stack-Ablaufverfolgung des Threads in jconsole oder jstack manuell abrufen und herausfinden, was los ist.

HINWEIS:jtop ist in Python geschrieben und erfordert, dass jstack installiert ist.

14
Josh Guilfoyle

Threads haben im Kernel keine Namen; Sie haben nur ID-Nummern. Die JVM weist Threads Namen zu. Dies sind jedoch private interne Daten innerhalb des Prozesses, auf die das "Top" -Programm nicht zugreifen kann (und die es sowieso nicht kennen).

4
Wyzard

Soweit ich herausfand, ist jstack veraltet ab JDK 8. Was ich zum Abrufen aller Java-Thread-Namen verwendet habe, ist:

<JDK_HOME>/bin/jcmd <PID> Thread.print

Überprüfen Sie die Dokumentation unter jcmd , um mehr zu erfahren.

2
Trinimon

Mit OpenJDK unter Linux werden die Namen von JavaThread nicht an native Threads weitergegeben. Sie können den Namen des Java-Threads nicht sehen, während Sie native Threads mit einem beliebigen Tool untersuchen.

Es sind jedoch einige Arbeiten in Arbeit:

Ich persönlich finde das OpenJDK-Entwicklungstool langsam. Ich verwende einfach Patches selbst.

2
milan

Dieses Shell-Skript kombiniert die Ausgabe von jstack und top, um Java-Threads nach CPU-Nutzung aufzulisten. Es erwartet ein Argument, den Kontonutzer, der die Prozesse besitzt.

Name: 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}"
1
Rick O'Sullivan

Alte Frage, aber ich hatte genau das gleiche Problem mit top.

Es stellt sich heraus, Sie können scrollen tops Ausgabe nach rechts, indem Sie einfach die Cursortasten verwenden :)

(aber leider wird kein Thread name angezeigt)

0
Scheintod

Wenn Sie auf Andre's eine frühere Antwort in Perl erweitern, wird hier eine in Python verwendet, die deutlich schneller läuft.

Dateien, die zuvor erstellt wurden, werden erneut verwendet, und die Jstack-Ausgabe wird nicht mehrmals wiederholt:

#!/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)
0

Sie haben "Linux" erwähnt. Dann könnte das kleine Tool "Threadcpu" eine Lösung sein:

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) ]

Einige Beispielausgaben:

$ 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

Die Ausgabe ist absichtlich sehr einfach, um die weitere Verarbeitung (z. B. zur Überwachung) einfacher zu gestalten.

0
reichhart