Linuxでプロセスの一覧を見たい
Linux環境で、プロセスの一覧を見たい場合に出てくるのは、ps
コマンドだと思います。
「今動いてるプロセスを見たい」、「このプロセス、今いるっけ?」といった声が挙がる場で、よく使われるコマンドだと思います。
注)本投稿は、Ubuntu Linux 18.04 LTSで確認しております
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic
オプションって、どうしましょうか?自分の観測範囲だと、以下の2つが多い気がします。
$ ps aux
$ ps -ef
-
がないのは、BSDスタイルオプションというやつですね。
出力例。
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 225536 8684 ? Ss 08:56 0:05 /sbin/init splash
root 2 0.0 0.0 0 0 ? S 08:56 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? I< 08:56 0:00 [kworker/0:0H]
root 6 0.0 0.0 0 0 ? I< 08:56 0:00 [mm_percpu_wq]
〜省略〜
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:56 ? 00:00:05 /sbin/init splash
root 2 0 0 08:56 ? 00:00:00 [kthreadd]
root 4 2 0 08:56 ? 00:00:00 [kworker/0:0H]
root 6 2 0 08:56 ? 00:00:00 [mm_percpu_wq]
〜省略〜
それぞれ、表示内容が異なりますね。
ps aux
だと、CPU使用率やメモリに関する情報が取得できます。ざっと確認するなら、まずはこちらで。
ps -ef
だと、親プロセスのID(PPID
)が表示されています。親プロセスが気になることもあるので、これはこれで便利です。
ちなみに、親子関係を見るだけならaux
オプションでもf
を足すと階層構造表示なら可能です。
$ ps auxf
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2 0.0 0.0 0 0 ? S 08:56 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? I< 08:56 0:00 \_ [kworker/0:0H]
root 6 0.0 0.0 0 0 ? I< 08:56 0:00 \_ [mm_percpu_wq]
root 7 0.0 0.0 0 0 ? S 08:56 0:01 \_ [ksoftirqd/0]
root 8 0.0 0.0 0 0 ? I 08:56 0:08 \_ [rcu_sched]
root 9 0.0 0.0 0 0 ? I 08:56 0:00 \_ [rcu_bh]
root 10 0.0 0.0 0 0 ? S 08:56 0:00 \_ [migration/0]
root 11 0.0 0.0 0 0 ? S 08:56 0:00 \_ [watchdog/0]
root 12 0.0 0.0 0 0 ? S 08:56 0:00 \_ [cpuhp/0]
〜省略〜
各オプションの意味ですが、こちらを参照。
-
a
… 端末を持つ全てのプロセスを表示する -
u
… ユーザー指向のフォーマットで表示する -
x
… 端末を持たない全てのプロセスを表示する -
-e
… 全てのプロセスを表示する -
f
… 階層表示する
特定の項目でソートしたい
ps
コマンドの結果を、特定の項目でソートしたいことがあるかもしれません。
k
(または--sort
)オプションを使いましょう。
例えば、以下のコマンドでCPU使用率でソートできます。
$ ps aux k -pcpu
メモリなら。
$ ps aux k -pmem
$ ps aux k -rss
k
の後に-フォーマット
で指定するのは、man
で見るか、以下のページを見たりするとよいでしょう。
スレッドのIDを表示したい
ps
コマンドに、-L
オプションを付けると、表示内容にLWP(軽量プロセスまたはスレッドのID)と、NLWP(プロセスにおけるスレッドの数)が追加されます。
$ ps aux -L | head -n 5
USER PID LWP %CPU NLWP %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 1 0.0 1 0.0 225536 8700 ? Ss 08:56 0:05 /sbin/init splash
root 2 2 0.0 1 0.0 0 0 ? S 08:56 0:00 [kthreadd]
root 4 4 0.0 1 0.0 0 0 ? I< 08:56 0:00 [kworker/0:0H]
root 6 6 0.0 1 0.0 0 0 ? I< 08:56 0:00 [mm_percpu_wq]
これで、プロセスから1段掘り下げて、スレッド単位でCPUの情報を見ることができます。
Javaのスレッドダンプと紐付けよう
なんとなく、表示されたLWPの情報とJavaのスレッドダンプと紐付けてみます。
Apache Tomcatで試してみましょう。ダウンロードして、起動。
$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-0ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
$ wget http://ftp.jaist.ac.jp/pub/apache/tomcat/tomcat-9/v9.0.14/bin/apache-tomcat-9.0.14.tar.gz
$ tar xf apache-tomcat-9.0.14.tar.gz
$ cd apache-tomcat-9.0.14
$ bin/startup.sh
jcmd
でスレッドダンプの取得。
$ jcmd [PID] Thread.print
ここでは、PIDが21017
のものを使って実例を見てみます。
nid=
の部分が、スレッドのIDです。
$ jcmd 21017 Thread.print | grep nid=
"Attach Listener" #44 daemon prio=9 os_prio=0 tid=0x00007f20bc001000 nid=0x5298 waiting on condition [0x0000000000000000]
"ajp-nio-8009-Acceptor-0" #42 daemon prio=5 os_prio=0 tid=0x00007f20fc7fa800 nid=0x5260 runnable [0x00007f206b0ef000]
"ajp-nio-8009-ClientPoller-1" #41 daemon prio=5 os_prio=0 tid=0x00007f20fc7f8800 nid=0x525f runnable [0x00007f206b1f0000]
"ajp-nio-8009-ClientPoller-0" #40 daemon prio=5 os_prio=0 tid=0x00007f20fc7dd800 nid=0x525e runnable [0x00007f206b2f1000]
"ajp-nio-8009-exec-10" #39 daemon prio=5 os_prio=0 tid=0x00007f20fc7c3000 nid=0x525d waiting on condition [0x00007f206b3f2000]
"ajp-nio-8009-exec-9" #38 daemon prio=5 os_prio=0 tid=0x00007f20fc7c1000 nid=0x525c waiting on condition [0x00007f206b4f3000]
"ajp-nio-8009-exec-8" #37 daemon prio=5 os_prio=0 tid=0x00007f20fc7bf000 nid=0x525b waiting on condition [0x00007f206b5f4000]
"ajp-nio-8009-exec-7" #36 daemon prio=5 os_prio=0 tid=0x00007f20fc7bd800 nid=0x525a waiting on condition [0x00007f206b6f5000]
"ajp-nio-8009-exec-6" #35 daemon prio=5 os_prio=0 tid=0x00007f20fc7bb800 nid=0x5259 waiting on condition [0x00007f206b7f6000]
"ajp-nio-8009-exec-5" #34 daemon prio=5 os_prio=0 tid=0x00007f20fc7ba000 nid=0x5258 waiting on condition [0x00007f206b8f7000]
"ajp-nio-8009-exec-4" #33 daemon prio=5 os_prio=0 tid=0x00007f20fc7b8800 nid=0x5257 waiting on condition [0x00007f206b9f8000]
"ajp-nio-8009-exec-3" #32 daemon prio=5 os_prio=0 tid=0x00007f20fc7b6800 nid=0x5256 waiting on condition [0x00007f206baf9000]
"ajp-nio-8009-exec-2" #31 daemon prio=5 os_prio=0 tid=0x00007f20fc770000 nid=0x5255 waiting on condition [0x00007f206bbfa000]
"ajp-nio-8009-exec-1" #30 daemon prio=5 os_prio=0 tid=0x00007f20fc76e000 nid=0x5254 waiting on condition [0x00007f206bcfb000]
"http-nio-8080-Acceptor-0" #29 daemon prio=5 os_prio=0 tid=0x00007f20fc76d000 nid=0x5253 runnable [0x00007f206bdfc000]
"http-nio-8080-ClientPoller-1" #28 daemon prio=5 os_prio=0 tid=0x00007f20fc76a000 nid=0x5252 runnable [0x00007f206befd000]
"http-nio-8080-ClientPoller-0" #27 daemon prio=5 os_prio=0 tid=0x00007f20fc768000 nid=0x5251 runnable [0x00007f206bffe000]
"http-nio-8080-exec-10" #26 daemon prio=5 os_prio=0 tid=0x00007f20fc765800 nid=0x5250 waiting on condition [0x00007f20d013b000]
-q
で、対象のPIDに絞ってプロセスの情報を表示。
$ ps aux -L -q 21017
USER PID LWP %CPU NLWP %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxxx 21017 21017 0.0 48 0.9 6979556 127592 pts/9 Sl 12:41 0:00 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.util.logging.config.file=.....
xxxxx 21017 21018 0.4 48 0.9 6979556 127592 pts/9 Sl 12:41 0:01 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.util.logging.config.file=.....
xxxxx 21017 21019 0.0 48 0.9 6979556 127592 pts/9 Sl 12:41 0:00 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.util.logging.config.file=.....
xxxxx 21017 21020 0.0 48 0.9 6979556 127592 pts/9 Sl 12:41 0:00 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.util.logging.config.file=.....
xxxxx 21017 21021 0.0 48 0.9 6979556 127592 pts/9 Sl 12:41 0:00 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.util.logging.config.file=.....
〜省略〜
ここでは、LWPが21067
のものを対象にしてみましょう。
jcmd
の結果だと、スレッドのIDは16進数表示だったので、例えばprintf
で表記変更します。
$ printf '%#x' 21067
0x524b
これをjcmd
の結果と合わせて、絞り込めばよいわけですね。
$ jcmd 21017 Thread.print | grep `printf '%#x' 21067`
"http-nio-8080-exec-5" #21 daemon prio=5 os_prio=0 tid=0x00007f20fc75c800 nid=0x524b waiting on condition [0x00007f20d0640000]
nid=0x524b
のスレッドがヒットしました。これを利用すると、CPUを消費しているスレッドを特定し、そのスタックトレースを見る、といったことができるようになります。
実際には、スタックトレースも一緒に見ると思うので、grep
で表示情報も絞ることはしないと思いますが、紐付けの参考として。