Linux 講座 / PIDとPPIDの理解 - プロセスの確認と管理

PID(Process ID、プロセスID)は実行中のプロセスを識別する番号で、PPID(Parent Process ID、親プロセスID)は現在の親のPIDです。Linuxでは対象の検索や親子関係の確認、必要なシグナルの送信に使います。番号はカーネルが割り当てるため、管理する対象は番号自体ではなく、その時点で実行中のプロセスです。

PIDとPPIDはどのように違うのでしょうか?

プロセスは実行中のプログラムの1つのインスタンスです。同じプログラムを2回実行すると、通常は互いに異なるPIDを持つ2つのプロセスが作成されます。別のプロセスが新しいプロセスを作成すると、新しいプロセスには親を指すPPIDも記録されます。

項目 意味 主な用途
PID 現在のプロセスの識別番号 特定のプロセスを照会したり信号を送ったりする時に使用
PPID 現在のプロセスの親プロセスPID 現在どのプロセスが親なのか、親子関係を確認

例えば、シェルのPIDが4250で、そのシェルで実行したsleepのPIDが4321である場合、sleepのPPIDは4250として表示されることがあります。この数字は説明用の例です。PIDはシステム全体で永久に固定される番号ではなく、終了後に別のプロセスに再利用されることがあります。コンテナのようにPID名前空間を使用する環境では、観察する名前空間によって同じプロセスのPIDが異なって見えることもあります。

現在のプロセスのPIDとPPIDを確認する

最も直接的な方法はpsで欲しい列を指定することです。次のコマンドは、Bashが$$を現在のシェルのPIDに展開した後、そのシェルの情報を表示します。

ps -p "$$" -o pid,ppid,user,stat,etime,args

出力は環境によって異なりますが、列の意味は以下の通りです。PIDはシェル自身の番号、PPIDはそのシェルを作成した親の番号です。USERは所有ユーザー、STATは状態、ELAPSEDは実行経過時間、COMMANDまたはARGSは実行コマンドを示します。

    PID    PPID USER     STAT     ELAPSED COMMAND
   4250    4110 learner  Ss         00:42 -bash

上記の数字とユーザー名は実測値ではなく例です。ps -p 4321 -o pid,ppid,argsのように指定できますが、元のプロセスが終了していれば該当行がないか、番号の再利用で別のプロセスが出る可能性があります。開始時刻や所有者も確認してください。全体の一覧にはps -eo pid,ppid,user,stat,argsを使い、長い出力はlessで確認できます。

プロセス名でPIDを探す場合は、pgrep -a -x sleepのように使用します。-xはプロセス名を正確に一致させ、-aはコマンドラインも表示します。同じ名前のプロセスが複数存在することがあるため、結果のPID一つだけを見て、それが探している作業だと断定しないでください。オプションや出力形式については、psコマンドの説明やpgrepコマンドの説明でも詳しく扱われています。

親・子関係を読み取り専用で確認する

プロセスを直接作成し、信号を送る基礎実習はプロセスとジョブ管理で行います。ここでは新しいプロセスを終了せず、現在のシェルと直接の子を確認します。ps自体が一時的な子として表示されることがあり、確認の間にプロセスが終了する場合もあります。

ps -p "$$" -o pid,ppid,user,lstart,args
ps --ppid "$$" -o pid,ppid,stat,args

対話型Bashでは、$$はそのシェルを示します。括弧で作られたBashサブシェルの中では、$$が親Bashの値として保持される場合があるため、現在のBashプロセスの値が必要な場合は$BASHPIDと区別してください。pstree -p "$$"はpstreeがインストールされている場合に選択的に使用できます。

PID名前空間と番号の再利用を区別する

同じプロセスであっても、ホストとコンテナで見えるPIDは異なる場合があります。以下のコマンドは現在のシェルが属するPID名前空間の識別子と、現在見えているprocファイルシステム上のPID階層情報を読み取ります。単一名前空間環境ではNSpidの数字がひとつしかない場合があり、カーネル・proc構成および権限によっては項目がなかったりアクセスが制限されたりすることがあります。

readlink "/proc/$$/ns/pid"
grep '^NSpid:' "/proc/$$/status"

名前空間の差は観察する場所による番号の差であり、PID再利用は前のプロセスが終了した後に番号を別のプロセスが受け取る現象です。両者を同じ現象として解釈したり、ホストとコンテナの番号を混ぜてシグナルを送ったりしないでください。

親が終了したりPIDが変わった場合はどうなりますか?

親を終了しても子が必ず一緒に終了するわけではありません。生きている子は、最も近い子サブリーパー(終了した子孫を引き取るよう設定された祖先プロセス)、または該当PID名前空間のinitなどに引き取られ、PPIDが変わることがあります。PPIDは作成者を永久に記録する値ではありません。親のPIDだけを終了すれば配下の作業もすべて止まるとは考えないでください。

逆に、子が終了しても親がまだ終了状態を回収していない場合、しばらくの間ゾンビプロセスとして残ることがあります。この状態の子はすでに実行を終えているため、そのPIDにKILLを繰り返し送る方法では解決しません。親プログラムの子回収動作を確認する必要があります。実習で使用したBashのwaitは、ちょうど自分が作った子の終了状態を受け取る例です。

PIDは実行中のプロセスを指す現在時点の識別子です。古いPIDファイルやメモに書かれた番号だけで終了対象を決めないでください。名前・所有者・開始時刻を合わせて確認し、コンテナの内外では異なるPIDネームスペースの番号を混同しないようにしてください。

サービスプロセスは何で管理しますか?

systemdで管理されているサービスは、プロセスが再起動する際にPIDが変わる可能性があります。この場合、PID一つに直接信号を送るよりも、サービス単位を確認して管理する方が適切です。例えば、nginx.serviceが実際にインストールされたシステムでは、systemctl status nginx.serviceで状態を確認し、運用上再起動が必要な場合にのみsudo systemctl restart nginx.serviceを使用します。nginxが存在しない、または別のサービスマネージャを使用する環境では、該当する名前と管理方法を確認する必要があります。

PIDはプロセスを正確に探す手がかりであり、PPIDはそのプロセスが持つ親子関係を理解する手がかりです。作業を停止する際には、名前検索だけで複数のプロセスに一括で信号を送るよりも、対象をまず絞り込み、システムサービスであればサービスマネージャに任せる方が安全です。

PIDネームスペースの文書および procステータスフィールドの文書で、観察範囲やNSpidフィールドを確認できます。

参考文書

ps(1)、pgrep(1)、pstree(1)、kill(1) の文書は、照会および信号送信の動作を説明します。Bash 特殊パラメータの文書 と Bash ジョブ制御の文書 は $$・$!・wait の意味を説明します。親の終了とゾンビ状態については wait(2) を参照できます。