ゾンビプロセス(zombie process)の正体と対処
ゾンビプロセスとは何か?
終了したのにプロセステーブルから消えないプロセスがゾンビプロセス(状態コード Z)。プロセス自体の実行はすでに終わっており、CPU・メモリは消費しない。ただし PID とプロセステーブルのエントリだけが残り続ける。
$ ps aux | grep Z
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND www-data 1234 0.0 0.0 0 0 ? Z 10:01 0:00 [defunct]
STAT 列が Z または [defunct] と表示されるのがゾンビの特徴。
なぜゾンビプロセスが発生するのか?
親プロセスが子の終了ステータスを回収していないことが原因。
Linux では子プロセスが終了すると、カーネルは終了ステータスをプロセステーブルに保存して親に SIGCHLD シグナルを送る。親が wait() / waitpid() でステータスを回収するまで、子のエントリはテーブルに残り続ける。
- 親が
wait()を呼ばずに子を終了させた - 親が
SIGCHLDハンドラを適切に実装していない - 親自体にバグがあり、シグナルを処理できない状態になっている
ゾンビは親プロセスが消えない限り自分では消えない。kill -9 をゾンビに送っても効果なし(すでに実行中ではないため)。
ゾンビプロセスの詳細な確認方法
親プロセスを特定する
$ ps -el | grep Z
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 Z 1000 1234 1100 0 80 0 - 0 - pts/0 00:00:00 process
PPID(親プロセス ID)が 1100 とわかる。次に親プロセスを確認する。
$ ps aux | awk 'NR==1 || $2==1100'
top でゾンビ数を監視する
$ top
Tasks: 142 total, 1 running, 141 sleeping, 0 stopped, 2 zombie
zombie の数が継続的に増加している場合は問題あり。
ゾンビプロセスの対処法
方法 1: 親プロセスに SIGCHLD を送る
親プロセスが SIGCHLD を処理できる実装なら、シグナルを送ると wait() を呼び出してゾンビを回収する。
$ kill -SIGCHLD <PPID>
方法 2: 親プロセスを終了させる
親が終了すると、子(ゾンビ)の養親が init(PID 1)または systemd に変わり、自動的に回収される。
$ kill <PPID>
親が応答しない場合:
$ kill -9 <PPID>
サービスプロセス(nginx、mysqld 等)を親ごと kill する場合は、サービスへの影響を事前に確認すること。
方法 3: システム再起動
ゾンビが大量発生して正常な状態に戻せない場合の最終手段。システム再起動でプロセステーブルは初期化される。
ゾンビプロセスは危険か?
少数のゾンビは実害なし。CPU・メモリを消費しないため、1〜2 個程度であれば即座に対処する必要はない。
ただし次の場合は問題になる:
- PID 枯渇: Linux のデフォルト PID 上限(
/proc/sys/kernel/pid_max)は 32768。ゾンビが大量に蓄積すると PID が尽き、新しいプロセスを起動できなくなる - プロセステーブルの肥大化: カーネルリソースを消費し続ける
現在の PID 上限確認:
$ cat /proc/sys/kernel/pid_max 32768
ゾンビを生まないアプリケーション設計
ゾンビはアプリケーションのバグが表出したもの。根本対処はコード修正。
SIGCHLDハンドラでwaitpid(-1, NULL, WNOHANG)をループ呼び出し- double fork パターンで孫プロセスを
initに引き取らせる SIGCHLDをSIG_IGNに設定する(POSIX 準拠の実装では子の自動回収が保証される)