はじめに
Linuxは多くのサーバやシステムの基盤として使われており、インフラエンジニアにとって欠かせない技術です。その中でも「プロセス管理」は、システムが安定して動作するために重要な知識のひとつですが、Linux OSがどのような方法でプロセスを管理しているのか、詳細に理解できていない方も多いのではないでしょうか。
本記事では、Linuxのプロセスの生成および状態遷移の概要について初心者の方でも理解できるように、基本からわかりやすく解説します。プロセスとは何か、どのように管理するのか、丁寧に紹介しますので、ぜひ最後までお読みいただき、日々の業務に役立ててください。
プロセスとは実行中のプログラム
プロセスとは実行中のプログラムを指します。ここで「実行中」とは、プログラムにメモリが割り当てられ、CPUによって命令が処理されている状態、またはCPUによる処理を待っている状態を意味します。
ではさっそく、Linuxマシン上で動作しているプロセスを確認してみましょう。Linuxサーバにてpsコマンド実行してみます。プロセス一覧を表示する際によく使われるオプションには、ps aux または ps -ef の2種類があります。用途に応じて使い分けてください。
• ps aux
CPU、メモリ使用率が確認可能です。%CPU、%MEMの項目を確認して下さい。
[root@appserver-dev ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.7 0.3 104968 13312 ? Ss 14:45 0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 31
root 2 0.0 0.0 0 0 ? S 14:45 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 14:45 0:00 [pool_workqueue_]
root 4 0.0 0.0 0 0 ? I< 14:45 0:00 [kworker/R-rcu_g]
root 5 0.0 0.0 0 0 ? I< 14:45 0:00 [kworker/R-sync_]
root 6 0.0 0.0 0 0 ? I< 14:45 0:00 [kworker/R-slub_]• ps -ef
親プロセス、子プロセスが確認可能です。PPIDという項目は親プロセスのPID(プロセスID)を指しています。
[root@appserver-dev ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 1 14:45 ? 00:00:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 31
root 2 0 0 14:45 ? 00:00:00 [kthreadd]
root 3 2 0 14:45 ? 00:00:00 [pool_workqueue_]
root 4 2 0 14:45 ? 00:00:00 [kworker/R-rcu_g]
root 5 2 0 14:45 ? 00:00:00 [kworker/R-sync_]
root 6 2 0 14:45 ? 00:00:00 [kworker/R-slub_]• pstree
各プロセスの親子関係を視覚的に表現することも可能です。
[root@appserver-dev ~]# pstree -p
systemd(1)─┬─NetworkManager(693)─┬─{NetworkManager}(699)
│ └─{NetworkManager}(700)
├─agetty(735)
├─auditd(644)───{auditd}(645)
├─chronyd(686)
├─crond(733)
├─dbus-broker-lau(675)───dbus-broker(677)
├─firewalld(680)───{firewalld}(973)
├─httpd(725)─┬─httpd(751)
│ ├─httpd(754)─┬─{httpd}(757)
│ │ ├─{httpd}(758)
│ │ ├─{httpd}(759)
│ │ ├─{httpd}(760)
│ │ ├─{httpd}(761)プロセス管理の方法
プロセスの生成
Linuxにおいて新しいプログラムを実行するためには、カーネルに対してシステムコールを発行し、プロセスを作成する必要があります。一般的には、fork と exec というシステムコールを使ってプロセスを生成します。イメージは下図のようになります。

• fork
fork はプロセスのコピーを生成するシステムコールです。コピー元のプロセスを「親プロセス」、コピー先のプロセスを「子プロセス」と呼びます。親プロセスのファイルディスクリプタ、環境変数、ユーザIDなどの情報はそのままコピーされますが、子プロセスには新しいPID(Process ID)が割り当てられます。
• exec
execは現在のプロセスを、指定したプログラムに置き換えるシステムコール群となります。PIDは変わりませんが、中身は完全に別のプログラムに置き換わります。
※forkのコピー処理
実際には、親プロセスのメモリ全てを即座にコピーするのではなく、仮想メモリと物理メモリの対応関係を管理するページテーブルがコピーされます。そして、親プロセスまたは子プロセスがページテーブルを書き換えようとした時点で初めて実際のメモリコピーが行われます。この仕組みは「Copy On Write(COW)」と呼ばれています。この仕組みによって、メモリの使用量を節約し、オーバーヘッドを抑えてforkの処理速度を向上させることが可能となっています。
プロセスの状態遷移
プロセスが生成された後は、下図のような状態遷移を行います。

• プロセス生成
プロセスが生成されると、実行可能状態に遷移します。
• 実行可能状態
CPUリソースの割り当てを待っている状態となります。 CPUの実行権を得られたら実行状態に遷移します。コンテキストスイッチ(※)という仕組みにより、実行可能状態と実行状態行き来する挙動となります。
• 実行状態
CPUが割り当てられ、処理が実行されている状態です。CPUが割り当てられた時間を経過すると、再び実行可能状態に遷移します。また、I/O待ちやリソースのロック待ちなどのイベントが発生すると、スリープ状態に遷移します。
• スリープ状態
イベント完了を待っている状態です。イベントが完了すると、実行可能状態に遷移します。
• プロセス終了
プログラムの処理が終わって、exitシステムコールが呼ばれるとプロセスが終了します。あるいはシグナルを使って強制的に終了させることもできます。
• ゾンビ状態
プロセスが終了した後、親プロセスが終了ステータスを取得(wait)しない場合、カーネルにプロセス情報が残った状態になります。これをゾンビ状態と呼びます。原因としては、プログラムのバグなどで親がwaitを行わないケースが挙げられます。
※コンテキストスイッチとは
論理CPU上で動作するプロセス、スレッドを切り替えることをコンテキストスイッチと呼びます。タイムスライスの時間が到来すると問答無用でコンテキストスイッチが発生して他の処理にCPUが使われます。Linuxにおけるコンテキストとは主にCPUレジスタの情報となります。実行中のプロセスを別のプロセスに切り替える際、現在のプロセスのコンテキストを保存し、次のプロセスの情報を復元します。
プロセス制御
シグナルによるプロセス制御
シグナルとは、プロセス間通信を行う際に使用される信号のことです。シグナルを受け取ったプロセスは、シグナルの指示に応じた処理を行います。良く使うシグナルとしては、下記のようなものがあります。
• SIGINT(シグナル番号:2)
プロセスに「割り込み」を要求するシグナルであり、デフォルトではプロセスが停止されます。コンソール操作時にキーボードから「Ctrl + c」と打つと送信されるシグナルです。ただし必ずプロセスが中断されるというわけではなく、プロセスがSIGINTを無視する設定になっていたり、SIGINTを受けて独自ロジックを実行するような設定になっている場合、プロセスが中断されないケースがあります。
• SIGTERM(シグナル番号:15)
プロセスを終了するシグナルです。シグナルの種類がオプションに指定されていない場合、デフォルトでは本シグナルが送信されます。
• SIGKILL(シグナル番号:9)
プロセスを即座に強制終了するシグナルです。SIGTERMで終了できなかった場合、本シグナルを送信して停止するケースがあります。kill -9 <PID>という形でコマンド実行するので「キルナイン」と呼んだりします。
※ゾンビプロセスはすでにプロセスが終了している状態なので、SIGKILLでも消すことはできません。親プロセスを終了させることでPID:1のinitに引き取らせたり、親プロセスにwait()を実行させることで削除します。
さいごに
Linuxのプロセス管理の機能についての説明は以上となります。本内容を理解していなくても普段の業務に支障はないかもしれませんが、いざトラブルが起きた時には非常に役立つ知識になります。本記事を通じて理解を深めていただけると幸いです。最後まで読んでいただき、ありがとうございました。
Linuxの処理概要については下記の記事でまとめてるので、興味ある方はこちらも参照ください。
インフラエンジニア入門|Linuxの歴史・機能概要・特徴をわかりやすく解説
参考文献



コメント