web-dev-qa-db-ja.com

topを使用したLinuxのJavaスレッドの検査

LinuxでJavaプロセスを使用して検査しています

top -H

ただし、「COMMAND」列でスレッドの名前を読み取ることができません(長すぎるため)。 「c」を使用してプロセスのフルネームを展開する場合、それはまだ長すぎます。

コマンドのフルネームを取得するにはどうすればよいですか?

35
Jake

ツールjstackを使用して、Javaスレッドを検査できます。指定されたプロセスpidに属するすべてのスレッドの名前、スタックトレース、およびその他の有用な情報をリストします。

編集:jstackのスレッドダンプ内のパラメーターnidは、スレッドのpid列にtopで表示されるLWPの16進数バージョンです。

26

これは少し古いかもしれませんが、topとjstackをマージするために私がやったことです。 2つのスクリプトを使用しましたが、すべて1つのスクリプトで実行できると確信しています。

最初に、topの出力をJavaスレッドのpidとともにファイルに保存し、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と呼びます)を呼び出し、2つのファイル(/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と、あちこちで微調整する必要があります。

24
Andre

JavaスレッドはCPU使用率で並べられたスレッドを視覚化するためのトップライクなコマンドを作成し、ソースコードを 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のインストールが必要です。

14
Josh Guilfoyle

私が知る限り、JDK 8の時点で jstackは古くなっています です。すべてのJavaスレッド名を取得するために使用したのは次のとおりです。

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

詳細については、 jcmd documentation を確認してください。

4
Trinimon

Linux上のOpenJDKでは、 JavaThread 名前が ネイティブスレッド に伝達されないため、Javaツール。

ただし、進行中の作業がいくつかあります。

個人的には、OpenJDK開発ツールが遅いので、自分でパッチを適用するだけです。

4
milan

カーネルに関する限り、スレッドには名前がありません。 ID番号のみがあります。 JVMはスレッドに名前を割り当てますが、それはプロセス内のプライベートな内部データであり、「トップ」プログラムはアクセスできません(とにかく知りません)。

3
Wyzard

このシェルスクリプトは、jstackとtopからの出力を組み合わせて、CPU使用率ごとにJavaスレッドをリストします。1つの引数、プロセスを所有するアカウントユーザーが必要です。

名前: 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

古い質問ですが、topでも同じ問題がありました。

カーソルキーを使用するだけでscroll topの出力を右に移動できます:)

(ただし、残念ながら、スレッドはありませんname表示)

0
Scheintod

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

出力は、さらに処理(監視など)をより簡単にするために、意図的に非常に単純です。

0
reichhart