このブログ記事では、Linuxにおけるプロセスについてを紹介します。

プロセスとは?
一般にプロセスとプログラムを同じものとして使う傾向がありますが、コンピュータサイエンスでは明確に区別されています。 プログラムは特定の命令のセットで構成されたコンパイル済みのコードであり、プロセスはそのプログラムを実行しているインスタンスを指します。 プロセスには、静的変数などのデータセクション、スタック、ヒープが含まれます。C/C++のようなコンパイル型言語でコードを書く場合、 コンパイルされた実行可能ファイルがプログラムであり、CPUやメモリ、ディスクなどのリソースが割り当てられることでプロセスとなります。
Pythonのようなインタープリタ型言語の場合、プログラムはインタープリタの実行ファイルであり、それが実行されることでプログラマが記述したスクリプト(通常はヒープに格納される)を解釈し、
リソースを割り当ててプロセスになります。このため、C/C++ではgccやg++のようなコンパイラでコードをコンパイルし、実行可能ファイルの場所を指定するだけですが、
PythonやNode.jsではpython <script_name>.py
やnode <script_name>.js
のように実行ファイルとスクリプト名の両方を指定します。
Linuxにおけるプロセス
Linuxでは、ps
コマンドを使って現在実行中のプロセスを確認できます。プロセスには一意のID(PID)が付与され、制御端末(TTY)の下で実行されています。
CPU使用時間とコマンドは、それぞれTIME列とCMD列に表示されます。
> ps
PID TTY TIME CMD
195 pts/1 00:00:00 bash
271 pts/1 00:00:00 ps
> ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4300 3428 pts/0 Ss+ Jan02 0:00 /bin/bash
root 8 0.0 0.0 4296 3652 pts/1 Ss Jan02 0:00 bash
root 194 0.0 0.0 5380 2432 pts/1 S Jan02 0:00 su - new
new 195 0.0 0.0 5240 4400 pts/1 S Jan02 0:00 -bash
new 272 0.0 0.0 8020 3380 pts/1 R+ 17:19 0:00 ps aux
ps aux
を使用すると、他のユーザによるプロセスも含めて、より多くの情報を確認できます。USER列には実効ユーザが表示され、%CPUと%MEMはCPU時間と物理メモリ使用量の割合、
VSZとRSSは仮想メモリ使用量とプロセスが使用する物理メモリ量(バイト単位)が表示されます。STATはプロセスの状態を示しています。(これについては後述します。)
プロセスの生成
Linuxを含むUnix系オペレーティングシステムでは、プロセスは常にfork
システムコールを使って生成されます。このコールは現在のプロセスを複製し、
異なるPIDを持つ親プロセスと子プロセスを作成します。一見すると冗長に思えますが、親プロセスのリソースがすでに設定されているため、
新しいプロセスをゼロから初期化するよりも簡単で柔軟な方法です。子プロセスはこれらのリソースを利用するか、新しいメモリ空間で新しいプログラムを実行するかを選択できます。
> ps l
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
4 1001 195 194 20 0 5240 4396 do_wai S pts/1 0:00 -bash
0 1001 270 195 20 0 8052 3644 - R+ pts/1 0:00 ps l
シェルプロセスに新しいプログラムの実行を指示すると、fork
システムコールがシェルプロセスを親プロセスとして扱い、その親プロセスID(PPID)を持つ新しい子プロセスが生成され、
指定されたプログラムを実行します。その後、親プロセスは子プロセスの終了状態を待つ(wait
システムコール)か、同時に自身のプログラムを実行し続けます。
ps l
コマンドを使用して、親プロセスID(PPID)を確認できます。例外はinitプロセスであり、これはPIDが1のプロセスで、カーネルが直接作成する最初のプロセスです。
initプロセスはすべてのプロセスの親となります。
プロセスの終了
通常、親プロセスはwait
システムコールを実行し、子プロセスがexit
システムコールを実行して使用していたリソースを解放するのを待ちます。
しかし、プロセスが終了に失敗する場合があります。その一例が、親プロセスが子プロセスの終了前に死んでしまった場合です。この場合、
子プロセスは孤児プロセスとなり、initプロセスが代わりにwait
を実行します。
もう一つの例は、親プロセスが子プロセスの終了前にwait
を実行できなかった場合です。この場合、子プロセスはゾンビプロセスとなります。
ゾンビプロセスはプロセステーブルに残り続け、親またはinitプロセスがwait
を実行しない限り削除されません。ゾンビプロセスは他のプロセスの実行を妨げる可能性があるため、
注意が必要です。
プロセスの状態
ps aux
やps l
コマンドのSTAT列はプロセスの状態を示します。たとえば、Rはプロセスが実行中または実行可能状態で、CPUの完了を待っていることを示します。
Sはプロセスがスリープ中で、特定のイベントを待っている状態です。Dは割り込み不可能なスリープ状態、Tは停止中のプロセス、Zは先述のゾンビプロセスを示します。
さらに、s
や+
などのサフィックスが付加されることがあります。これらは、プロセスがセッションリーダーであることや、フォアグラウンドプロセスグループに属していることを示します。
PROCESS STATE CODES
Here are the different values that the s, stat and state output
specifiers (header "STAT" or "S") will display to describe the state of
a process:
D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by
its parent
For BSD formats and when the stat keyword is used, additional
characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads
do)
+ is in the foreground process group
上記はman ps
のSTATについての説明です。セッションはプロセスグループやジョブのコレクションであり、一意のセッションID(SID)を持ちます。
このSIDの値は、セッションリーダーのPIDと同じです。セッションは、異なるユーザーやデーモンプロセス(バックグラウンドで実行され、ユーザーの制御を離れるプロセス)のプロセスやジョブを分離するために設定されます。
ジョブ
プロセスグループやジョブは、プロセスをターミナルウィンドウをブロックするフォアグラウンドで実行するか、ターミナルウィンドウをブロックしないバックグラウンドで実行するかを制御するために設定されています。
Linuxでは、コマンドの末尾に&
を追加することでプロセスをバックグラウンドジョブとして実行できます。また、Ctrl+Zを使用してプロセスを一時停止し、その後bg
コマンドで現在のプロセスをバックグラウンドジョブに移動することも可能です。
バックグラウンドジョブを表示するには、jobs
コマンドを使用します。
> sleep 1000 &
> sleep 1001 &
> sleep 1002
^Z
[3]+ Stopped sleep 1002
> bg
[3]+ sleep 1002 &
> jobs
[1] Running sleep 1000 &
[2]- Running sleep 1001 &
[3]+ Running sleep 1002 &
上は、ジョブに関連するコマンドの使用例を示しています。ジョブリストの+
は、バックグラウンドジョブに追加された最新のプロセスを示し、-
は2番目に最新のプロセスを示します。
バックグラウンドジョブのプロセスをフォアグラウンドに移動するには、fg %<ジョブ番号>
、または最新のジョブの場合は%+
、その前のジョブの場合は%-
を使用できます。
シグナル
コマンドで何かミスをした場合、Ctrl+Cを押してプロセスを中断することができます。これは、プロセスに割り込みを送るためのSIGINTシグナルのショートカットです。 シグナルは列挙型(enum)のようなもので、それぞれに対応する番号があります。SIGINTの場合、その値は2です。シグナルを使用すると、 プロセスに何らかのイベントが発生したことを通知できます。
- SIGHUP or HUP or 1: Hangup
- SIGINT or INT or 2: Interrupt
- SIGKILL or KILL or 9: Kill
- SIGSEGV or SEGV or 11: Segmentation fault
- SIGTERM or TERM or 15: Software termination
- SIGSTOP or STOP: Stop
上は、ユーザーやプロセスが使用できるシグナルの一覧です。プロセスはほとんどのシグナルに対してどのように対処するかを決定することができるため、
どのシグナルを使用するかは慣例に依存する場合が多いです。SIGHUPは通常、プロセスをバックグラウンドプロセスグループに送るために使用され、
ユーザーが現在のターミナルから切断するたびに送信されます。また、手動で送信することも可能です。一方、SIGINTはプロセスを中断しますが、
バックグラウンドには送信されません。この動作は、jobs
コマンドを使用して確認できます。
> kill -<SIGNAL> <PID>
上は、kill
コマンドを使用してプロセスにシグナルを送信する方法を示しています。シグナルを指定しない場合、デフォルトでSIGTERMシグナルが送信されます。
ただし、送信したいシグナルに対応する番号を指定することで、特定のシグナルを指定されたPIDのプロセスに送信することが可能です。
プロセスの詳細
プロセスの詳細を確認および追跡する方法は他にもあります。例えば、ps m
コマンドを使用すると、プロセス内のスレッドを確認できます。
スレッドは軽量で、同じメモリを共有し、プロセス内での通信が容易であり、切り替えが高速であるという点でプロセスとは異なります。
また、Linuxではすべてがファイルとして扱われるため、cat /proc/<PID>/status
を使用して、プロセスの詳細が保存されているファイルを確認することもできます。
top
コマンドは、10秒ごとにプロセスとリソースの使用状況を追跡します。このツールは非常に便利で、ps
で確認できるすべての情報に加え、
ロードアベレージ(1分、5分、15分間でCPU時間を待機しているプロセスの数)、CPU使用率、メモリ使用状況、優先度(nicenessレベル)などの統計情報を確認できます。
nicenessレベルは、nice -n 5 <コマンド>
で初期設定したり、renice 10 -p <PID>
で再設定したりできます。
結論
この記事では、プロセスの定義、生成方法、終了方法、追跡および設定方法について説明しました。さらに深く理解するために、下記のリンクやリソースをぜひ参照してください。
また、sar
のような便利なプロセス継続監視ツールも試してみることをお勧めします。
リソース
- GeeksForGeeks. 2024. How to Monitor System Activity in Linux | top Command. GeeksForGeeks.
- Linux Journey. n.d. Processes. Linux Journey.
- Linux Journey. n.d. Process Utilization. Linux Journey.