killできないプロセスとゾンビプロセスの調査・対処|Dステート・defunctの見分け方と安全な解消手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxトラブルシューティング > killできないプロセスとゾンビプロセスの調査・対処|Dステート・defunctの見分け方と安全な解消手順
「kill -9 を打ったのにプロセスが消えない」「ps aux で Z や D が表示されたまま何も変わらない」。夜間の障害対応でこういう場面に遭遇すると、焦りながら何度も kill を打ち直してしまいます。

しかし、ゾンビプロセス(defunct)とDステートプロセスに kill コマンドを何度打っても解消しません。どちらもカーネルの仕組み上、シグナルを受け取れる状態にないからです。

この記事では、「ゾンビプロセス kill できない」「Dステート kill できない」という状況の根本原因から、ps・/proc ファイルシステムを使った調査手順状態ごとの安全な解消方法まで、RHEL 9.4 / Rocky Linux 9 の実際のサーバー出力例を交えて解説します。闇雲に kill を繰り返すのではなく、状態を正確に診断して的確な対処が取れるようになることがゴールです。

この記事のポイント

・ゾンビ(defunct/Z)は「終了済みの残骸」でシグナルを受け取れない
・Dステートは「カーネルI/O待ちで割り込み不可」のため kill が効かない
・ゾンビ解消には kill ではなく「親プロセスへの SIGCHLD か親の終了」が正解
・DステートはNFS・ストレージのI/O根本原因を取り除かないと解消しない


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

ゾンビプロセス(defunct)とDステートプロセスはなぜkillできないのか

まず前提として、Linux カーネルにおけるプロセスの「状態(State)」を整理します。ps aux の STAT 列に表示される一文字がプロセスの現在の状態を表しており、kill コマンドで送れるシグナルが効くかどうかは、この状態に完全に依存します。

下表にプロセス状態と kill の有効性をまとめます。

STAT 状態名 kill シグナルの効果 代表的な原因
R Running(実行中 / 実行待ち) 有効 CPU 上で実行中
S Sleeping(割り込み可能スリープ) 有効 I/O 待ちだが割り込み可
D Disk Wait(割り込み不可スリープ) 無効(I/O 完了まで保留) NFS 応答なし、ストレージI/O停止
Z Zombie(ゾンビ) 無効(実行コードがない) 親プロセスが wait() を呼んでいない
T Stopped(停止中) SIGCONT か SIGKILL のみ有効 SIGSTOP / Ctrl+Z

ゾンビとDステートで kill が効かない理由は、それぞれ全く異なるメカニズムによるものです。

1. ゾンビプロセスに kill が効かない理由

ゾンビプロセスとはすでに実行を終えたプロセスの「抜け殻」です。プロセスは終了すると、自分の終了ステータスをカーネルのプロセステーブルに記録して待機します。この終了ステータスを親プロセスが wait() 系システムコールで回収するまでの間、プロセステーブル上のエントリが残り続けます。

この状態にあるプロセスには、実行すべきコードが一切存在しません。CPU もメモリも消費していません。プロセステーブルのスロット 1 つを占有しているだけです。そのため、SIGKILL(シグナル 9)を送っても「受け取るコードが存在しない」ため、何も起こりません。

2. DステートプロセスにSIGKILLが効かない理由

Dステート(uninterruptible sleep)のプロセスは、カーネルの重要なI/O処理の途中にあります。NFS マウントへのファイル読み書きや、ストレージドライバとのやり取りなど、中断すると整合性が崩れる処理の中にいる状態です。

Linux カーネルは、このような「割り込んではいけない」処理の中にいるプロセスをDステートとしてマークし、シグナルの配送を一時的にブロックします。SIGKILL もシグナルの一種であるため、Dステート中は配送が保留され、I/O が完了するか、またはI/Oがエラーで終了するまでずっと待ち続けます。

NFS サーバーが応答を返さない場合のように、I/O がいつまでも終わらない状況では、Dステートのプロセスはシステムを再起動するまで解消しないことがあります。

ゾンビプロセス(defunct)の正体と調査手順

ゾンビプロセスの調査は「どの親プロセスがゾンビを生み出しているか」を特定することが目的です。ゾンビ本体は無害ですが、大量に発生している場合は親プロセスのバグを示しているため、放置すべきではありません。

1. ゾンビプロセスの検出

まず ps コマンドでゾンビプロセスの一覧を確認します。STAT 列に「Z」が付いているプロセスがゾンビです。

# ゾンビプロセスのみを抽出する $ ps -eo pid,ppid,stat,comm | grep ' Z' PID PPID STAT COMMAND 3412 3401 Z php-fpm 3419 3401 Z php-fpm 4892 4880 Z worker.py

上記の例では、PID 3401 の親プロセスの子として php-fpm ゾンビが 2 つ、PID 4880 の親の子として python ゾンビが 1 つ発生しています。

ps aux の表示では COMMAND 列に「[プロセス名] <defunct>」と表示されます。

$ ps aux | awk '$8 ~ /Z/' USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND www-data 3412 0.0 0.0 0 0 ? Z 10:23 0:00 [php-fpm] <defunct> www-data 3419 0.0 0.0 0 0 ? Z 10:24 0:00 [php-fpm] <defunct> appuser 4892 0.0 0.0 0 0 ? Z 11:05 0:00 [worker.py] <defunct>

2. 親プロセス(PPID)の特定

ゾンビプロセスの PPID から親プロセスを特定します。

# ゾンビの親PIDを取り出す $ ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/ {print $2}' | sort -u 3401 4880 # 親プロセスの詳細を確認する $ ps -p 3401 -o pid,ppid,stat,comm,cmd PID PPID STAT COMMAND CMD 3401 1 S php-fpm php-fpm: master process (/etc/php-fpm.conf)

3. /proc ファイルシステムで詳細を確認する

ゾンビプロセスの /proc エントリには、終了ステータスなどの最低限の情報が残っています。

$ cat /proc/3412/status Name: php-fpm State: Z (zombie) Tgid: 3412 Pid: 3412 PPid: 3401 ... VmPeak: 0 kB VmSize: 0 kB

VmSize が 0 kB であることに注目してください。ゾンビプロセスはメモリを消費していないことが分かります。消費しているリソースはプロセステーブルのエントリ 1 つだけです。

4. ゾンビ数が多い場合のシステムへの影響

Linux のプロセスIDには上限(通常は 32768、/proc/sys/kernel/pid_max で確認可)があります。ゾンビが大量に蓄積するとプロセスIDが枯渇し、新しいプロセスを起動できなくなります。

# 現在のゾンビ数を確認する $ ps -eo stat | grep -c '^Z' 127 # pid_max の上限を確認する $ cat /proc/sys/kernel/pid_max 32768

ゾンビが 100 を超えてきたら、原因となっている親プロセスのバグを優先して調査・修正する必要があります。

Dステート(uninterruptible sleep)プロセスの正体と調査手順

Dステートプロセスは「何かを待っている」状態です。何を待っているかを突き止めることが解消への第一歩です。

1. Dステートプロセスの検出

# Dステートプロセスの一覧を確認する $ ps -eo pid,ppid,stat,comm | grep ' D' PID PPID STAT COMMAND 891 2 D kworker/u4:2 2244 2230 D python3 5512 5500 D rsync

STAT 列が「D」で始まるプロセスがDステートです。「Ds」「D+」のように後ろにフラグが付く場合も同じです。

2. wchan で「何を待っているか」を確認する

/proc/PID/wchan には、プロセスが待機しているカーネル関数名が記録されています。これが Dステート調査の核心情報です。

# 待機しているカーネル関数を確認する(NFS の場合の例) $ cat /proc/2244/wchan nfs_file_read # rsync がブロックしている場合の例 $ cat /proc/5512/wchan nfs_lock_inode_wait # ディスクI/O待ちの場合の例 $ cat /proc/891/wchan io_schedule

wchan の値から原因を推測できます。

nfs_*:NFSマウントへのI/O待ち → NFSサーバーの応答不能を疑う
io_schedule:ブロックデバイスのI/O待ち → ストレージの異常を疑う
mutex_lock* / wait_event*:カーネル内ロック待ち → ドライバのバグの可能性

3. カーネルスタックで詳細を確認する

root 権限があれば /proc/PID/stack でカーネルスタックの詳細を確認できます。これにより待機の連鎖を追うことができます。

# カーネルスタックを確認する(root権限が必要) $ sudo cat /proc/2244/stack [<0>] nfs_file_read+0x72/0xe0 [nfs] [<0>] new_sync_read+0x12d/0x1c0 [<0>] vfs_read+0xa4/0x1a0 [<0>] ksys_read+0x5f/0xe0 [<0>] do_syscall_64+0x3b/0x90 [<0>] entry_SYSCALL_64_after_hwframe+0x72/0xdc

スタックの最上位(先頭行)が現在ブロックしている場所です。この例では NFS のファイル読み込み関数で止まっていることが分かります。

4. dmesg でカーネルメッセージを確認する

DステートはカーネルがI/Oエラーを記録していることが多く、dmesg に手がかりがあります。

$ dmesg | tail -30 [1234567.890] nfs: server 192.168.10.50 not responding, timed out [1234580.123] nfs: server 192.168.10.50 not responding, still trying [1234621.456] INFO: task python3:2244 blocked for more than 120 seconds. [1234621.457] Not tainted 5.14.0-427.13.1.el9_4.x86_64 #1 [1234621.458] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.

「blocked for more than 120 seconds」はカーネルの hung task 検出メッセージです。この PID を突き合わせると Dステートプロセスの原因が即座に特定できます。

5. lsof でオープンファイルを確認する

Dステートプロセスがどのファイルやソケットを開いたままブロックされているかは、lsof コマンドで確認できます。

# Dステートプロセスのオープンファイルを確認する $ sudo lsof -p 2244 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME python3 2244 appuser cwd DIR 0,46 4096 123456 /mnt/nfs_share python3 2244 appuser 0u CHR 136,0 0t0 3 /dev/pts/0 python3 2244 appuser 1u CHR 136,0 0t0 3 /dev/pts/0 python3 2244 appuser 4r REG 0,46 1073741824 789012 /mnt/nfs_share/data/large_file.bin

cwd(カレントディレクトリ)や開いているファイルが NFS マウントポイント(この例では /mnt/nfs_share)を指している場合、NFS の問題が原因です。

ゾンビプロセスを安全に消す方法:親プロセスへのアプローチ

ゾンビプロセスを消すには、親プロセスに「子プロセスを回収してください」と伝えるか、親プロセスを終了させてカーネル(init/systemd)にゾンビを引き取らせるかの、2 つのアプローチがあります。

1. 親プロセスに SIGCHLD を送って子を回収させる

適切に実装されたプログラムは SIGCHLD シグナルを受け取ると wait() を呼び出してゾンビを回収します。まずこの穏やかな方法から試します。

# 親PIDに SIGCHLD を送る(PPID=3401 の場合) $ kill -CHLD 3401 # または数値シグナルで指定する $ kill -17 3401 # 送信後にゾンビが消えたか確認する $ ps -eo pid,ppid,stat,comm | grep ' Z' (何も表示されなければ回収成功)

ただし、バグのあるプログラムや SIGCHLD を無視する設定のプロセスでは効果がない場合があります。

2. 親プロセスを kill して systemd にゾンビを引き取らせる

SIGCHLD が効かない場合、または親プロセスを停止して問題ないと判断した場合は、親プロセスを終了させます。親プロセスが終了すると、そのゾンビ子は PID 1(systemd / init)に引き取られ、systemd が自動的に wait() を呼んで回収します。

# 親プロセスを穏やかに終了させる(SIGTERM) $ kill 3401 # 数秒待ってゾンビが消えたか確認する $ ps -eo pid,ppid,stat,comm | grep ' Z' # SIGTERM で終了しない場合は SIGKILL(サービスの場合は systemctl で管理する方が安全) $ kill -9 3401

注意:親プロセスが Web アプリや DB のマスタープロセスである場合、kill するとサービスが停止します。サービス管理下にあるプロセスは systemctl restart サービス名 で再起動するほうが安全です。

# php-fpm サービスを再起動する(これでゾンビも一緒に解消される) $ sudo systemctl restart php-fpm # 再起動後の確認 $ ps -eo pid,ppid,stat,comm | grep ' Z' (ゾンビが消えていることを確認)

3. 親プロセスが PID 1(systemd)の場合

稀に親プロセスが PID 1 の systemd そのものである場合があります。この場合、systemd が何らかの理由で wait() を遅延させているケースが多く、通常はしばらく待つと自動回収されます。systemd 自体を kill することは絶対に行わないでください。

# PPIDが1のゾンビを確認する $ ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/ && $2 == 1 {print}' # systemd に孤児プロセス回収を促す(SIGCHLD を PID 1 に送る) $ sudo kill -CHLD 1

Dステートプロセスの解消手順と判断フロー

Dステートの解消は、I/O ブロックの原因を取り除くことが唯一の正解です。原因が解消されると、待機中のシステムコールがエラーを返し、プロセスが D から抜けます(正常終了か、プログラム内のエラーハンドリングが動く)。

1. NFS マウントが原因の場合

wchan に nfs_ が含まれる場合は NFS が原因です。NFS サーバーとの通信を確認します。

# NFS マウント一覧を確認する $ mount | grep nfs 192.168.10.50:/export/data on /mnt/nfs_share type nfs (rw,relatime,...) # NFS サーバーへの疎通を確認する $ ping -c 3 192.168.10.50 # または $ showmount -e 192.168.10.50 # 強制アンマウント(-l は lazy unmount、-f は force) $ sudo umount -l -f /mnt/nfs_share

強制アンマウント後、Dステートプロセスが D から抜けてプロセスが終了または再実行されることを確認します。

# アンマウント後のプロセス状態確認 $ ps -eo pid,ppid,stat,comm | grep ' D' (Dステートが解消されていれば何も表示されない)

NFS マウントを soft オプション-o soft,timeo=30,retrans=3)で設定しておくと、タイムアウト後にI/Oがエラーを返すため Dステートになりにくくなります。

2. ブロックデバイス(HDD/SSD)のI/Oエラーが原因の場合

wchan が io_schedule または blk_mq_* 系の場合は、ストレージデバイスのI/Oエラーを疑います。

# ストレージのI/Oエラーを確認する $ dmesg | grep -E 'I/O error|ata[0-9]+|blk_update_request' [1234567.890] blk_update_request: I/O error, dev sdb, sector 1048576 [1234568.012] ata2.00: exception Emask 0x0 SAct 0xf00 SErr 0x0 action 0x6 [1234568.014] ata2.00: irq_stat 0x40000008 # iostat でデバイスのI/O状況を確認する $ iostat -x 1 3

物理ディスクのI/Oエラーが原因の場合、当該デバイスの交換が必要になります。RAID 構成であれば縮退稼働したうえでデグレード状態を確認し、ディスク交換と再ビルドを行います。

3. それでも解消しない場合の最終手段

NFS 強制アンマウントやデバイス確認でも Dステートが解消しない場合、カーネルパニックを起こさずにシステムを再起動するのが最も安全な手段です。

# 通常の再起動(シャットダウンプロセスを経由) $ sudo systemctl reboot # シャットダウンプロセスが Dステートで詰まった場合は magic SysRq を使う # (/proc/sys/kernel/sysrq が 1 の場合のみ有効) $ echo 1 | sudo tee /proc/sys/kernel/sysrq $ echo b | sudo tee /proc/sysrq-trigger # ※ echo b は即時リブート(ファイルシステムの同期なし)。最終手段として使う

SysRq による即時リブートはファイルシステムの同期を行わないため、ファイル破損のリスクがあります。まず echo s | sudo tee /proc/sysrq-trigger(sync)を実行してからリブートするとリスクを軽減できます。

両者を素早く見分けるチェックリスト

障害対応中に状況を素早く把握するためのチェックリストです。

# ゾンビとDステートを一発で確認するコマンド $ ps -eo pid,ppid,stat,comm | awk '$3 ~ /^[ZD]/' PID PPID STAT COMMAND 891 2 D kworker/u4:2 2244 2230 D python3 3412 3401 Z php-fpm

確認項目 ゾンビ(Z) Dステート(D)
STAT 列 Z(または Zs, Z+) D(または Ds, D+)
COMMAND 列 [プロセス名] <defunct> 実際のコマンド名
CPU / メモリ消費 0%(リソースを消費しない) 低いが長時間継続すると高くなる
kill -9 の効果 無効 無効(I/O完了後に効く場合あり)
調査コマンド ps -eo pid,ppid,stat でPPID確認 cat /proc/PID/wchan で待機関数確認
解消方法 親プロセスへ SIGCHLD / 親プロセスを終了 I/O根本原因の解消(NFS再マウント等)
緊急度 大量でなければ低い(CPU/メモリ影響なし) 高い(プロセスが進まずサービスに影響)

再発防止策とカーネルメッセージの読み方

1. ゾンビ再発防止:アプリケーション側の修正

ゾンビが継続的に発生する場合、親プロセスのコードに wait() が実装されていないか、シグナルハンドラで SIGCHLD を無視(SIG_IGN)に設定しているバグがあることがほとんどです。

C/C++ アプリwaitpid(-1, NULL, WNOHANG) を SIGCHLD ハンドラ内でループ呼び出しする
Python アプリsignal.signal(signal.SIGCHLD, signal.SIG_DFL) でデフォルトに戻すか、subprocess モジュールの .wait() を適切に呼ぶ
シェルスクリプト:バックグラウンドプロセスには wait コマンドを対応させる

2. Dステート再発防止:NFS マウントオプションの見直し

NFS マウントの際に hard(デフォルト)ではなく soft オプションを使うと、タイムアウト後に I/O がエラーを返すため Dステートになりにくくなります。

# /etc/fstab での NFS soft マウントの設定例 # 192.168.10.50:/export/data /mnt/nfs_share nfs soft,timeo=30,retrans=3,_netdev 0 0 # コマンドラインでのマウント例 $ sudo mount -o soft,timeo=30,retrans=3 192.168.10.50:/export/data /mnt/nfs_share

ただし soft マウントはデータ整合性のリスクがあるため、書き込みを伴うマウントには慎重に適用します。読み取り専用(ro)の NFS マウントであれば soft を積極的に活用できます。

3. カーネルの hung task タイムアウト設定

カーネルは 120 秒以上 Dステートが続くプロセスを「hung task」として dmesg に記録します。この値は調整可能です。

# 現在の hung task タイムアウト値を確認する $ cat /proc/sys/kernel/hung_task_timeout_secs 120 # 検知を早める場合(本番環境では慎重に) $ echo 60 | sudo tee /proc/sys/kernel/hung_task_timeout_secs # 永続化する場合は /etc/sysctl.d/99-hung-task.conf に記述する # kernel.hung_task_timeout_secs = 60

4. 定期監視スクリプトの例

Dステートやゾンビの発生を早期に検知するための簡単な監視スクリプトの例です。

#!/bin/bash # プロセス異常状態の監視スクリプト(cron で 5 分ごとに実行) ZOMBIE_COUNT=$(ps -eo stat | grep -c '^Z') DSTATE_COUNT=$(ps -eo stat | grep -c '^D') if [ "$ZOMBIE_COUNT" -gt 10 ]; then logger -t proc-monitor "WARNING: Zombie count is ${ZOMBIE_COUNT}" fi if [ "$DSTATE_COUNT" -gt 5 ]; then logger -t proc-monitor "CRITICAL: D-state count is ${DSTATE_COUNT}" # カーネルメッセージを記録する dmesg | tail -20 | logger -t proc-monitor fi

このスクリプトを cron に登録しておき、/var/log/messages に記録された警告を Zabbix や Prometheus で拾う構成にすることで、障害の早期発見につながります。

プロセスのトラブルシューティングをさらに深く学ぶには、Linux 基本コマンドの解説も合わせてご覧ください。

まとめ

ゾンビプロセスとDステートプロセスは、どちらも「kill -9 が効かない」という現象が同じでも、原因も対処法も全く異なります。状態を正しく見極めることが障害対応の出発点です。

やりたいこと コマンド / 手順
ゾンビ一覧を確認する ps -eo pid,ppid,stat,comm | grep ' Z'
Dステート一覧を確認する ps -eo pid,ppid,stat,comm | grep ' D'
ゾンビの親PIDを取り出す ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/ {print $2}' | sort -u
Dステートの待機関数を確認する cat /proc/PID/wchan
Dステートのカーネルスタックを確認する sudo cat /proc/PID/stack
親プロセスにゾンビ回収を促す kill -CHLD PPID
NFSマウントを強制解除する sudo umount -l -f /mnt/マウントポイント
カーネルのI/Oエラーを確認する dmesg | grep -E 'I/O error|not responding|hung'
hung task タイムアウトを確認する cat /proc/sys/kernel/hung_task_timeout_secs
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Linux Master Pro Seminar の詳細を見る >>

ゾンビとDステートの仕組みを理解することで、kill を繰り返す無駄な時間を削減し、障害の根本原因に素早くたどり着けるようになります。Linux の障害対応スキルをもっと体系的に身につけたい方は、ぜひ下のセミナー情報もご覧ください。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。