\r\n\r\n
プログラムの書き方や実行方法が悪いと、Linuxコンピュータにゾンビプロセスが潜んでいることがあります。ゾンビはどのように作られ、最終的にどのように鎮めることができるのかを学びます。
Linuxはもちろん、コンピュータ上で動作しているすべてのアプリケーションやデーモンを把握しておかなければならない。その一つの方法として、プロセステーブルを整備する。カーネルメモリ内の構造体の一覧です。各プロセスは、このリストにエントリーを持ち、そのプロセスに関するいくつかの情報を含んでいます。
各プロセステーブルの構成は、あまり内容がありません。プロセスID、その他のデータ項目、そのプロセスのプロセスコントロールブロック(PCB)へのポインタが含まれます。
PCBは、Linuxが各プロセスを検索したり設定する必要がある多くの詳細を保持します。PCBはまた、プロセスが作成され、処理時間が与えられ、最終的に破棄されるときに更新されます。
Linux PCBには95以上のフィールドがあります。PCB は、task_struct.h という構造体で定義され、700 行以上の長さがあります。
プロセス状態」は、以下のいずれでもよい。
Zombie状態で子プロセスが生成されると、親プロセスはwait()関数群のいずれかを呼び出します。そして、子プロセスの状態変化を待ちます。子プロセスは、停止、継続、終了のいずれかのシグナルを受けたか?実行中のコードの自然な終了で終了するか?
状態の変化が子プロセスの実行停止を意味する場合、その終了コードが読み込まれる。その後、子 PCB は破棄され、プロセステーブルのエントリが削除されます。理想的なのは、このすべてが瞬時に行われ、ゾンビ状態のプロセスは長くは存在しないことです。
関連:Linuxでバックグラウンドプロセスを実行・制御する方法
親プロセスの書き方が悪いと、子プロセスを生成するときに wait() 関数を呼び出さないことがあります。これは、子プロセスの状態変化を何も監視していないことを意味し、SIGCHLDシグナルは無視されることになる。あるいは、別のアプリケーションが親プロセスの実行に影響を与えている。これは、プログラミングの不備や悪意が原因である可能性がある。
しかし、親プロセスが子プロセスの状態変化を監視しなければ、適切なシステムハウスキーピングは行われない。子プロセスが終了しても、PCBやプロセステーブルのエントリを削除しない。これにより、ゾンビの状態がPCBから削除されることはありません。
ボットはある程度のメモリを必要としますが、通常は問題を起こしません。プロセステーブルのエントリは小さいが、プロセスIDは解放されるまで再利用できない。64ビットOSでは、PCBはプロセステーブルのエントリよりはるかに大きいので、これは何の問題も発生しないと思われます。
ご想像の通り、大量のゾンビが発生すると、他のプロセスが利用できるメモリ量に影響を与えます。しかし、それだけのゾンビがいるのであれば、親アプリケーションやオペレーティングシステムに重大な問題があることになります。
ゾンビプロセスはすでに死んでいるので、殺すことはできない。メモリから削除され、SIGKILL信号を送信する場所がないため、いかなる信号にも応答しません。親プロセスにSIGCHLDシグナルを送ってみることもできますが、子プロセスが終了したときにうまくいかなかったのであれば、現在もうまくいくとは思えません。
唯一の確実な解決策は、親プロセスを終了させることです。終了すると、その子プロセスは、Linuxシステム上で最初に動作するプロセスであるinitプロセス(プロセスIDは1)に継承されます。
initプロセスは定期的に必要なボットのクリーンアップを行うので、ボットを殺すには、ボットを作ったプロセスを殺すだけでよい。 topコマンドは、ボットがあるかどうかを確認する便利な方法である。
と入力する。
topこのシステムには8つのゾンビプロセスがあります。psコマンドを使用し、egrepにパイプすることでこれらを一覧することができます。この場合も、ゾンビプロセスのステータスフラグは "Z" で、通常は "defunct" も表示されます。
と入力する。
ps aux | egrep "Z|defunct"ゾンビプロセスが掲載されます。
ボットプロセスIDを見つけるには、上部を何度もスクロールするよりもずっとすっきりした方法です。また、これらのボットを生成する「badprg」というアプリケーションも確認されました。
最初のゾンビのプロセスIDは7641ですが、その親のプロセスIDを見つける必要があります。再びpsを使用します。出力オプション(-o)を使用して、親のプロセスIDのみを表示するようにpsに指示し、それをppid=flagで渡します。
探しているプロセスは、-p(プロセス)オプションを使用して、ゾンビのプロセスIDを渡すことで表示されます。
そこで、プロセス7641のプロセス情報を検索するために以下のコマンドを入力しますが、親プロセスのIDしか報告されません。
ps -o ppid= -p 7641親プロセスIDが7636であることがわかります。これで再びpsを使って相互参照することができます。
直前の親プロセスの名前と一致していることがわかる。親プロセスを終了させるには、以下のようにSIGKILLオプションとkillコマンドを併用します。
kill -SIGKILL 7636親プロセスのオーナーによっては、sudoを使用する必要がある場合もあります。
...巨大な大群でない限り。恐れるに足らず、単純な再起動で一掃されるものもいくつかある。
しかし、あるアプリケーションやプロセスが常にボットを生成していることに気づいたら、これを調べる必要があります。おそらく急ごしらえのプログラムであり、その場合、子プロセスの後に適切にクリーンアップできるアップデート版が存在する可能性があります。