問題:プロセステーブルに潜む幽霊先日、動作が「重い」と感じる本番サーバーを調査しました。CPUやRAMの使用率は10%程度で安定していましたが、システムが新しいタスクを開始させてくれませんでした。プロセスの状況を素早く確認したところ、<defunct> とラベル付けされたエントリが数十個も見つかりました。これらが「ゾンビ」プロセスです。
ゾンビプロセスとは、処理は完了しているものの、プロセステーブルに残っているタスクのことです。これは、親プロセスが wait() システムコールを介して子プロセスの終了ステータスを確認(受信)できなかった場合に発生します。ゾンビプロセスはアクティブなメモリを消費しませんが、決して無害ではありません。
ゾンビプロセスの特定システムがゾンビに憑依されていないか確認するには、次のコマンドを実行します。
ps aux | grep '<defunct>'
以下のような出力が表示された場合、クリーンアップ作業が必要です。
user 1234 0.0 0.0 0 0 ? Z 10:00 0:00 [my-app] <defunct>
STAT列の Z が決定的な証拠です。PID 1234はCPUサイクルを消費していませんが、カーネルのプロセステーブルのスロットを占有し続けています。多くのシステムのデフォルト制限は32,768 PID(cat /proc/sys/kernel/pid_max で確認可能)です。この上限に達すると、サーバーは新しいプロセスを一切生成できなくなります。
なぜ kill -9 が効かないのか反射的に kill -9 1234 を実行したくなるかもしれませんが、残念ながらゾンビには効果がありません。すでに死んでいるものを殺すことはできないからです。ゾンビは単なるデータの残骸であり、親プロセスが最終的に「回収(reap)」するまでカーネルが保持している幽霊のような存在です。
ゾンビを消去するには、**親プロセス(Parent Process)**に対処する必要があります。親プロセスにバグがあったり、ハングアップしていたり、作りが不適切だったりすると、子の終了シグナルを無視してしまい、ゾンビが放置されることになります。
ステップ1:親PID(PPID)を見つける問題の原因となっているプロセスを特定するために、以下のコマンドを使用します。
ps -o ppid= -p [ZOMBIE_PID]
ゾンビのPIDが1234の場合、コマンドは以下のようになります。
ps -o ppid= -p 1234
これで親PIDが返されます。ここでは仮に1100としましょう。
解決策:クリーンアップ段階的なアプローチをお勧めします。他のサービスをクラッシュさせないよう、まずは最も影響の少ない方法から試してください。
方法1:「つつく」(SIGCHLD)親プロセスが単に他の処理で忙しいだけの場合もあります。シグナルを送って、子の状態を確認するように促すことができます。
kill -s SIGCHLD 1100
この SIGCHLD シグナルは、子の状態が変化したことを親(PID 1100)に伝えます。適切に設計されたアプリケーションであれば、これに反応して wait() を呼び出し、ゾンビは即座に消滅します。
方法2:サービスの再起動「つつく」方法で解決しない場合、親プロセスが無限ループやデッドロック状態に陥っている可能性があります。重要度の低いサービスであれば、再起動が最も早い解決策です。
systemctl restart my-service-name
親プロセスが終了すると、そのゾンビの子プロセスは「孤児(orphans)」になります。Linuxはこの状況を完璧に処理します。孤児になったプロセスは即座に PID 1(systemd または init)に養子入りします。PID 1は、引き取ったゾンビをクリーンアップするために設計された「究極の死神(ultimate reaper)」です。
方法3:親プロセスの強制終了(最終手段)サービスを正常に再起動できない場合は、親プロセスを強制終了させる必要があるかもしれません。
kill -9 1100
親プロセスがいなくなると、カーネルはゾンビをPID 1に渡し、PID 1が即座に回収します。この方法は、親プロセスが重要な処理を行っていないことが確実な場合にのみ使用してください。
検証:修正の確認作業後は必ず確認を行ってください。最後にもう一度チェックを実行し、プロセステーブルがクリーンであることを確認します。
ps aux | grep '<defunct>' | grep -v grep
出力が空であれば、ゾンビは退治されました。また、top や htop のヘッダーにある「zombie」の数を確認し、再び増え始めないか監視するのも良いでしょう。

