Linuxのプロセス:ps、top、htop、kill、シグナル、nice
Linux のプロセスは ps aux(その時点のスナップショット)、top と htop(更新される一覧と負荷)で確認します。kill PID は既定で穏やかな SIGTERM を送ります。kill -9(SIGKILL)は、プロセスが反応しない場合にだけ使います。優先度は起動時の nice と、実行中のプロセスに対する renice で設定します。値の範囲は -20 から 19 です。
Linux で動いているプログラムはすべてプロセスであり、PID という番号、所有者、状態、優先度を持っています。プロセスは ps、top、htop で確認でき、kill で終了させ、nice と renice で優先度を変えられます。ここでは、これらのコマンドの出力の読み方、どのシグナルをいつ送るべきか、そして kill -9 を最初に使うべきではない理由を見ていきます。
プロセスと PID とは
プロセスは実行中のプログラムです。コード、メモリ、開いているファイル、属性の集合を持ちます。カーネルは各プロセスに一意の識別子 PID を割り当て、起動元の番号 PPID も記録します。システムで最初のプロセス(PID 1)は通常 systemd で、ほかのすべてのプロセスの「親」になります。
新しいプロセスは2つのステップで生まれます。まず親が fork() を呼び出して自分のコピーを作ります。次にコピーが execve() を呼び出し、自分のコードを新しいプログラムのコードに置き換えます。ターミナルで ls と入力すると、bash はまさにこの処理を行い、wait() で子の終了を待ちます。
$ echo $$ # 現在のシェルの PID
4182
$ ps -o pid,ppid,cmd -p $$
PID PPID CMD
4182 4170 -bash
ps コマンドでプロセスを確認する
ps はその時点のスナップショットを表示して終了します。引数なしで実行すると、現在のターミナルのプロセスだけが表示されます。実際には次の2つのどちらかを使うことがほとんどです。
$ ps aux | head -5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 168540 12780 ? Ss 09:12 0:03 /sbin/init
root 2 0.0 0.0 0 0 ? S 09:12 0:00 [kthreadd]
www-data 1532 1.2 2.1 412308 86420 ? S 09:15 1:47 php-fpm: pool www
postgres 1610 0.4 3.8 221004 154312 ? Ss 09:15 0:31 postgres: checkpointer
a はすべてのユーザーのプロセス、u は所有者を含む詳細な形式、x は端末を持たないプロセス(デーモン)も含むことを意味します。System V 形式の ps -ef も使えます。こちらは PPID を表示するので、どのプロセスがどのプロセスを起動したかを調べるときに便利です。
| 列 | 意味 |
|---|---|
PID | プロセスの識別子 |
%CPU、%MEM | プロセッサと物理メモリの使用率 |
VSZ | 仮想メモリ(KB 単位、RAM に載っていない分を含む) |
RSS | 実際に使用している物理メモリ(KB 単位) |
STAT | 状態(R、S、D、Z、T)とフラグ |
TIME | 累積の CPU 時間。実行時間ではありません |
ps の便利な使い方
# メモリを多く使う上位 10 件
ps aux --sort=-%mem | head -11
# CPU を多く使う上位 10 件
ps aux --sort=-%cpu | head -11
# 表示する列を指定
ps -eo pid,ppid,user,ni,stat,etime,cmd
# プロセスのツリー表示
ps -ef --forest
pstree -p
# 名前から PID を探す
pgrep -a nginx
pidof nginx
よくある間違いは ps aux | grep nginx で探すことです。この場合、出力に grep 自身も含まれてしまいます。pgrep を使うか、grep [n]ginx のように書いてください。このパターンは、grep 自身のコマンドラインには一致しません。
プロセスの状態:R、S、D、Z、T
STAT 列の文字は飾りではなく、プロセスの実際の状態を示します。負荷の読み方や、kill が効くかどうかは、この状態によって変わります。
| コード | 状態 | 実際の意味 |
|---|---|---|
R | Running | 実行中、または CPU の順番待ち |
S | Interruptible sleep | イベント(ネットワーク、入力、タイマー)を待っている。多くのプロセスの通常の状態 |
D | Uninterruptible sleep | カーネル内で I/O の完了を待っている。シグナルは届かない |
Z | Zombie | 終了済みだが、親が終了コードを回収していない |
T | Stopped | SIGSTOP または Ctrl+Z で一時停止中 |
文字のあとに付く記号も役に立ちます。s はセッションリーダー、+ はターミナルのフォアグラウンドプロセス、< は高い優先度、N は低い優先度、l はマルチスレッドであることを示します。
状態 D のプロセス
D のプロセスはシステムコールの途中で、たとえばディスクや応答しない NFS の応答を待っています。このプロセスにはシグナルが届かず、SIGKILL であっても効きません。そのため kill -9 は役に立ちません。待ちの原因を調べる必要があります。iostat、dmesg、ネットワークストレージの状態を確認してください。
ゾンビプロセス
ゾンビはすでに終了しています。CPU もメモリも使わず、プロセステーブルに1行分の場所を占めるだけです。すでに終了しているため、kill で消すことはできません。親が wait() を呼ぶか、親自身が終了してゾンビが PID 1 に引き取られると消えます。
# ゾンビとその親を探す
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
1つだけのゾンビは害がありません。数百に増え続けている場合は、親のプログラムにバグがあるので、修正するか再起動してください。
top:リアルタイムのプロセスと負荷
top は同じプロセス一覧を数秒ごとに更新し、システム全体の概要も表示します。「サーバーが遅い」と感じたときに最初に実行するコマンドです。
top - 14:21:07 up 12 days, 3:02, 2 users, load average: 1.84, 1.20, 0.95
Tasks: 213 total, 2 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.1 us, 4.2 sy, 0.0 ni, 70.3 id, 1.9 wa, 0.0 hi, 0.5 si, 0.0 st
MiB Mem : 7821.4 total, 412.6 free, 3105.8 used, 4303.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4398.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1532 www-data 20 0 412308 86420 14212 R 38.2 1.1 1:47.31 php-fpm
1610 postgres 20 0 221004 154312 148900 S 6.0 1.9 0:31.08 postgres
%Cpu(s) の行が最も重要です。us はユーザー空間のコード、sy はカーネル、id はアイドル、wa はディスクの待ち時間です。CPU に空きがあるのに wa が高い場合は、I/O がボトルネックである明確な兆候です。
top のキー操作
| キー | 動作 |
|---|---|
P / M | CPU / メモリで並べ替え |
1 | CPU コアを個別に表示 |
c | コマンドライン全体を表示 |
u | ユーザーで絞り込み |
k | プロセスにシグナルを送る |
r | プロセスの nice 値を変更 |
H | スレッドを表示 |
q | 終了 |
スクリプトやログ向けには、バッチモードがあります。top -b -n 1 | head -20 は対話なしで1回分のスナップショットを表示します。特定のプロセスだけを監視するには top -p 1532 を使います。
Load Average はパーセントではなく待ち行列
load average の3つの数値は、直近 1、5、15 分間の実行待ちキューの平均長です。Linux では、R と D の状態のプロセスがキューに入ります。通常の S のスリープは含まれません。LA は CPU コア数(nproc)と比べて評価します。4 コアで値が 4 なら全力稼働、12 なら処理能力の 3 倍の待ち行列があることになります。
LA が高いのに CPU がアイドルの場合は、D 状態のプロセスを探してください。ps -eo stat,pid,cmd | grep '^D' で確認できます。多くの場合、遅いディスクやネットワークストレージが原因です。
htop:top の使いやすい代替
htop は同じ情報を、CPU コアごとのカラーメーター、スクロール、マウス操作、プロセスツリーとともに表示します。通常は別途インストールが必要です。例:sudo apt install htop または sudo dnf install htop。
F3または/:名前でプロセスを検索F4:一致するものだけを表示するフィルターF5またはt:親子関係のツリー表示F6:並べ替えの列を選択F7/F8:nice 値を下げる、上げるF9:選択したプロセスへのシグナルのメニューSpace:複数のプロセスを選択して一括操作
何もインストールできないサーバーでは top で十分です。主な操作はすべて top にもあります。
kill でプロセスを終了する:シグナル
kill は実際には「殺す」のではなく、プロセスにシグナルを送ります。その後の動作は、シグナルの種類と、プログラムがそれをどう扱うかによって決まります。
| シグナル | 番号 | 用途 |
|---|---|---|
SIGHUP | 1 | 端末の切断。多くのデーモンは設定を再読み込みする |
SIGINT | 2 | 割り込み。Ctrl+C と同じ |
SIGKILL | 9 | カーネルによる強制終了。捕捉できない |
SIGTERM | 15 | 丁寧に終了を依頼する。kill の既定 |
SIGSTOP | 19 | 一時停止。捕捉できない |
SIGCONT | 18 | 一時停止したプロセスを再開 |
SIGTSTP | 20 | 端末からの一時停止。Ctrl+Z |
番号は x86 と ARM の場合です。全一覧は kill -l で表示できます。番号より名前で指定する方が確実です。
kill 1532 # SIGTERM
kill -TERM 1532 # 同じ(明示的に指定)
kill -HUP $(pidof nginx) # 設定を再読み込み
kill -STOP 1532; kill -CONT 1532
kill -0 1532 && echo "プロセスは生きています"
シグナル 0 は何も送らず、プロセスが存在し、そこに信号を送る権限があるかだけを確認します。スクリプトで便利です。
なぜ最初に kill -9 を使うべきではないのか
SIGTERM を受け取ったプログラムは、ファイルを閉じ、バッファを書き出し、ロックファイルを削除し、トランザクションを正しく終了できます。SIGKILL はすべてを即座に打ち切ります。書きかけのデータは失われ、一時ファイルは残り、データベースは次回の起動時にリカバリが必要になることがあります。
正しい手順は次のとおりです。
kill PID(SIGTERM)を送る。- 5〜30 秒待ち、
kill -0 PIDで確認する。 - プロセスがまだ生きていて、状態が
Dでない場合にのみkill -9 PIDを使う。
systemd のサービスは、PID を手で扱わないのが理想です。systemctl stop が SIGTERM を送り、タイムアウトを待ち、最後に SIGKILL で止めてくれます。
pkill と killall:名前で終了させる
pkill -f "python worker.py" # コマンドライン全体で一致
pkill -u alice # ユーザーのすべてのプロセス
killall -TERM node # 名前が node のすべてのプロセス
pgrep -l -f worker # 一致するものを先に確認
大量に pkill を使う前には、同じパターンで pgrep を実行してください。-f はコマンドラインのどの部分にも一致するので、関係のないプロセスまで対象になりがちです。
シグナルを送れるのは自分のプロセスだけです。他人のプロセスには sudo が必要です。Operation not permitted というエラーは、この意味です。
優先度:nice と renice
nice の値は、どのプロセスが CPU を譲るべきかをスケジューラーに伝えます。範囲は -20(最も高い優先度)から 19(すべてに譲る)で、既定値は 0 です。top では NI 列に表示され、PR は内部で計算される実効的な優先度です。
# 重いタスクを低い優先度で起動
nice -n 10 tar czf backup.tar.gz /var/www
# 実行中のプロセスの優先度を下げる
renice -n 15 -p 1532
# 優先度を上げる(root のみ)
sudo renice -n -5 -p 1610
# ユーザーのすべてのプロセス
sudo renice -n 10 -u alice
一般ユーザーは、自分のプロセスの優先度を下げることしかできません。負の値は root だけが設定できます。nice の効果は CPU にしか及ばない点に注意してください。システムがディスクで遅くなっている場合は、ionice -c3 コマンド を使います。これはアイドルクラスで、ほかに誰もディスクを使っていないときだけ I/O を実行します。
バックグラウンドプロセスとジョブ制御
コマンドは末尾に & を付けるとバックグラウンドで実行できます。Ctrl+Z で一時停止することもできます。シェルはジョブの一覧を管理し、組み込みコマンドで操作します。
$ long_task &
[1] 5120
$ jobs
[1]+ Running long_task &
$ fg %1 # フォアグラウンドに戻す
^Z # 一時停止(SIGTSTP)
$ bg %1 # バックグラウンドで再開
ターミナルを閉じると、シェルはジョブに SIGHUP を送り、ジョブは終了します。終了後も動かし続けるには nohup コマンド & で起動するか、disown で切り離すか、tmux を使います。恒久的に動かすなら、systemd のサービスとして登録するのが適切です。
典型的な診断シナリオ
CPU を使い切っているのは誰か
top -o %CPU # または top の中で P
ps -eo pid,user,%cpu,etime,cmd --sort=-%cpu | head
無駄に CPU を使っているプロセスがあれば、まず renice で優先度を下げてください。安全で、原因を調べる時間を確保できます。
ポートを使用しているのは誰か
sudo ss -ltnp | grep :8080
sudo lsof -i :8080
出力に PID が表示されます。その PID を使うと、/proc/PID/ の中で実行ファイル(exe)、作業ディレクトリ(cwd)、引数(cmdline)を確認できます。
プロセスが突然消えた
よくある原因は OOM Killer です。メモリが不足したときにカーネルがプロセスを強制終了します。確認方法は dmesg -T | grep -i oom または journalctl -k | grep -i "killed process" です。
まとめ
Linux のプロセス管理に必要なのは、少数のコマンドです。スナップショットには ps aux、監視には top と htop、終了には適切なシグナルを付けた kill、優先度には nice と renice を使います。行動する前にプロセスの状態を確認してください。ゾンビや状態 D のプロセスは、シグナルでは直りません。まず SIGTERM から始め、kill -9 は最後の手段にとっておきましょう。プロセス、メモリ、Load Average、システムコールは、Linux コースで実践しながら詳しく解説しています。
よくある質問
ps aux と ps -ef の違いは何ですか?
どちらも同じコマンドの2つの書式です。aux は BSD 形式で %CPU、%MEM、STAT の列を表示し、-ef は System V 形式で PPID の列を表示します。どちらも表示されるプロセスは同じで、システム上のすべてのプロセスです。
システムで何個のプロセスが動いているかを知るには?
最も簡単なのは top の Tasks 行を見ることです。または ps -e --no-headers | wc -l を実行してください。スレッドの数は ps -eLf --no-headers | wc -l で確認できます。
kill -9 を使ってもプロセスが終了しないのはなぜですか?
状態 D でカーネル内の I/O を待っているか、すでに終了しているゾンビのどちらかです。前者はディスクやネットワークストレージの問題を調べ、後者は親を修正または再起動してください。
PID 1 を終了させるとどうなりますか?
カーネルは init を保護しています。init が処理しない限り、ユーザーからの SIGKILL を含む通常のシグナルは届きません。もし init が終了すると、システムはカーネルパニックに陥ります。
プロセスのメモリ使用量を制限するには?
systemd のサービスなら、ユニットファイルに MemoryMax= を設定します。一度だけ起動する場合は systemd-run --scope -p MemoryMax=500M コマンド を使います。これは cgroups を使うため、古い ulimit -v より確実です。