Lesson 9

プログラムの実行と停止、その他の管理

Lesson 9 Chapter 1
プロセスについて

初めに

Lesson8では、メモリ、CPU、ストレージ、I/Oリソースの状態管理について学習をしました。 Lesson9では、実行したプログラムの状態管理の仕方について学習します。 これは、実行中のプログラムのコンピュータへの負荷状況把握と、 安定したシステム稼働の実現に役立てることができます。

本レッスンではChapter3で具体的な状態管理のためのコマンドを学習します。 Chapter1とChapter2では、Chapter3で学ぶために必要な、プロセス、ジョブの概念について、説明を行います。

プログラムとプロセス

プログラムとは、何らかの処理をコンピューターにさせるための手順を記述したファイルです。 プログラムと似たもので、プロセスという概念があります。 プロセスとは、実行されて動作中のプログラムを指します。 プログラムはそれ自体単なるファイルなので、ディスクに保存される以外にコンピュータ上のリソースを消費しません。 対して、プロセスは処理を完了するまで、メモリ、CPU、I/O等のリソースを消費します。

区分 内容 消費するリソース
プログラム コンピューターにさせる処理の手順を記載したファイル ディスクに保存する分だけストレージを消費する。
プロセス 実行されて動作中のプログラム 処理が完了するまでメモリ、CPU、I/Oリソースを消費する。

私たちは既に沢山のプログラムを実行してきました。 例えば「シェルのcdコマンドを実行した時」「vimを起動した時」というのは、cdコマンドやvimに関するプログラムを実行していたのです。 その他身近な例を挙げると、windowsでエクセルを立ち上げた時にはエクセルのプログラムが、ブラウザを立ち上げた時にはブラウザのプログラムが実行されています。

ユーザーモードとカーネルモード

プログラムが実行される場合、Linuxでは「ユーザーモード」か「カーネルモード」のいずれかのモードで実行されます。 二つのモードの違いは下表のとおりです。

モード 内容
ユーザーモード デバイスにアクセスしてデータの書き込みをすることが出来ない。
カーネルモード デバイスへのアクセスに制限はなく、データの書き込みを行える。

通常のプログラムはユーザーモードで実行され、デバイスに直接データの書き込みはできません。 それは、通常のプロセスが直接デバイスに書き込みをすることが出来てしまうと、二つ以上の異なるプログラムが、デバイス上の「まったく同じ領域」にデータを書き込んでしまう恐れがあるからです。 デバイス上の「まったく同じ領域」に二つのプログラムから書き込みが行われた場合、初めに書き込まれたデータはなくなってしまいます。

そこで、プロセス実行中にデバイスへ書き込みを行うような処理があった場合、プロセスはカーネルへ制御を譲ります。 そして全てのリソースを一元管理できるカーネルのみが、カーネルモードで書き込みを実行するようになっているのです。

initプロセス

プロセスは必ず元となるプロセスから生成されます。 この元となるプロセスを「親プロセス」、生成されたプロセスを「子プロセス」といいます。 initプロセスは、システム起動時に特別に発行されるプロセスで、全てのプロセスの親となるプロセスです。

ゾンビプロセス

Linuxでは、プロセスが終了する時、子プロセスから親プロセスへ、プロセスが終了したことを伝えるようになっています。 プロセス終了の情報が無事伝わったのちに、プロセスは消滅します。 ところが、何らかの原因により、プロセスの終了状態が親プロセスへ伝わらない場合、その子プロセスは何の働きもしない一方、リソースを占有し続けます。 このようなプロセスをゾンビプロセスといいます。

一般的に、親プロセスは定期的に子プロセスが終了したかを確認するため、親プロセスにバグなどがなければ、ゾンビプロセスが増え続けることはありません。

シグナル

プロセスが通常どおり削除されずゾンビプロセスとなった場合に、外部から強制的にプロセスの状態を変更することができます。 プロセスの状態を変更するために送る信号を、シグナルといいます。

プロセスを外部から強制的に削除するには、後のChapterで紹介するkillコマンドを使用します。 killコマンドは、指定したプロセスに対して、プログラムを終了する旨のシグナルを送り、プロセスを消滅させます。

なお、誤って自作のプログラムが無限ループしてしまった時に「ctrl + c」で強制的にプログラムを終了することがあると思いますが、 この操作も、プログラムに対して、終了する旨のシグナルを送っています。

Lesson 9 Chapter 2
ジョブについて

ジョブとは

コマンドラインから一行で実行されたプログラムの処理を、ジョブといいます。 ジョブとプロセスは一見似ているようですが、一つのジョブの中に複数のプロセスが含まれる場合があります。

例えば$ ls /home/とコマンドを打った時には一つのジョブの中に、一つのプロセスが含まれますが、 $ ls /etc/ | lessとパイプラインで複数のコマンドを繋げて実行した場合、同一ジョブに複数のプロセスが属します。

また、ジョブはシェルごとに管理され、それぞれにIDが振られます。 対して、プロセスには全てのシェルをまたいでIDが振られます。 従って、ユーザーが発行したプロセスのIDは「1980」や「3320」等の大きい数字が振られやすいですが、ジョブIDは「1」や「10」といったように比較的小さい数字が振られます。

フォアグランドジョブとバックグランドジョブ

ジョブはフォアグランドジョブとバックグラウンドジョブの二つに分類することが出来ます。 両者の違いは下表のとおりです。

ジョブ 内容
フォアグラウンドジョブ 実行されて、ユーザーの操作対象となっているジョブ。そのジョブが終了するまで端末画面には次のプロンプトが表示されず、一つのシェルにつき一つしか実行できない。
バックグラウンドジョブ 実行されているが、ユーザーの操作対象とはなっていないジョブ。一つのシェルにつき複数同時に実行できる。

以降Chapter3では、ジョブがフォアグラウンドジョブになることを「フォアグラウンドに移行」、バックグラウンドジョブになることを「バックグラウンドに移行」と呼びます。

Lesson 9 Chapter 3
プロセスとジョブの照会・管理

このチャプターではプロセスやジョブを照会したり管理できるコマンドをご紹介いたします。

pidof

pidofコマンドは、指定したプロセスに一致するプロセスIDを一覧表示することができます。 書式は以下です。

pidof <オプション> <プロセス名>

以下では引数に「bash」を指定して、bashシェルのプロセスIDを表示しています。

 $ pidof bash
 1276

このように、プロセスIDが「1276」だということがわかりました。 後ほど紹介予定のkillコマンドの引数にこのIDを与えて実行すると、プロセスを削除することができます。

pidstat

pidstatコマンドは、プロセス単位でCPU使用率やI/Oデバイスの使用状況を表示することができます。 また、pidstatコマンドは以前にご紹介したmpstatコマンドと同じく、sysstatパッケージに収録されています。 まだダウンロードが完了していない場合$ yum install sysstatを実行してインストールしてください。 pidstatコマンドの書式は以下です。

pidstat <オプション> <更新間隔(回数)>

では早速pidstatコマンドの後ろに「5」と「2」を入力して実行してみましょう。

 $ pidstat 5 2
 Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain)   2022年11月10日   _x86_64_    (1 CPU)

 02:07:09 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
 02:02:10 PM     0       559    0.00    0.99    0.00    0.99     0  X
 02:02:10 PM   321        18    0.00   14.85    0.00   14.85     1  gnome-shell
 02:02:10 PM   321        48    0.99    0.00    0.00    0.99     0  pidstat

 02:02:09 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
 02:02:10 PM     0       559    0.00    0.99    0.00    0.19     0  X
 02:02:10 PM 54321        18    0.00   12.85    0.00   10.35     1  gnome-shell
 02:07:10 PM 54321        48    0.99    0.00    0.00    0.49     0  pidstat

上記は5秒間で2回の統計を表示させる意味になります。オプションを指定しない場合は上記統計情報が一度だけ出力されます。 続いて、メモリ統計を表示させるためには-rオプションを使います。

 $ pidstat -r 2 2
 Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain)   2022年11月10日   _x86_64_    (1 CPU)
  
 02:04:29 PM   UID       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
 02:04:30 PM 54321      3944      2.96      0.00  113444  62080   9.09  X
 02:04:30 PM 54321      6212    619.01      0.00  108432   2400   0.13  pidstat 
  
 02:04:30 PM   UID       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
 02:04:31 PM 14221      3863      1.35      0.00    3444    080   4.09  X
 02:04:31 PM 14221      6443      2.87      0.00    2476    860   2.18  gnome-shell
 02:04:31 PM 14221      6211      4.65      0.00    8432   2452   8.14  pidstat

また、プロセスI/Oの統計を表示させるためには-dオプションを指定します。

 $ pidstat -d
 Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain)   2022年11月10日   _x86_64_    (1 CPU)
 02:04:29 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
 02:04:29 PM 54321      3852      0.00     31.37      0.00  X

 02:04:29 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command

 平均値:     UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
 02:04:29 PM 54321      3852      0.00     31.37      0.00  X

このようにpidstatコマンドは、オプションを使って監視対象を絞ることができます。

top

topコマンドは、プロセスごとにCPU使用率やメモリ使用率などの情報を確認することができます。 実行中のプロセスの起動確認や動作検証などで使われます。

基本書式は以下のとおりです。

ps <オプション>

指定できるオプションは以下になります。

オプション 詳細 使用例
-d 指定した時間(秒)間隔で結果を出力する $ top -d 1
-u 指定したユーザーの実行中プロセスを表示する $ top -u vboxuser
-n 指定した回数分topコマンドの結果を出力する $ top -n 3
-p 指定したプロセスID(PID)の結果を出力する $ top -d 1

それではtopコマンドの出力内容を確かめるために、以下を実行してください。

 $ top

すると、このように表示されます。 修了させたい場合はqキーを入力してください。

 top - 12:37:18 up  3:47, 1 users,  load average: 0.00, 0.01, 0.05
 Tasks:  193 total,   4 running,  189 sleeping,   0 stopped,   0 zombie
 %Cpu(s)  :  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
 KiB Mem :  9614652 total,    65500 free,   122292 used,   786860 buff/cache
 KiB Swap:   999996 total,   903996 free,    96000 used.   659044 avail Mem

 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
   1 root      20   0       0      0      4 S   0.0  0.2   1:49.13 systemd
   2 root      20   0       0      0      0 S   0.0  0.0   0:00.80 kthreadd
   4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
   6 root      20   0       0      0      0 S   0.0  0.0   0:13.20 ksoftirqd/0
   7 root      rt   0       0      0      0 S   0.0  0.0   0:01.00 migration/0

出力結果が上段と下段に分かれています。 上段の各箇所の意味は下表のとおりです。

箇所 内容
top - 12:37:18 up 3:47, 現在時刻が12時37分18秒で、OS起動から3時間47分経過している。
1 users, サーバーへ一人がログインしている。
load average : 0.00, 0.01, 0.05 ディスクI/O(読込、書込)待ち状態のプロセス数。数値が高いとパフォーマンスに悪い影響を及ぼしている。
Tasks: 193 total, 4 running, 189 sleeping, 0 stopped, 0 zombie 現在193個のプロセスが存在し、内4個が実行中、189個がスリープ状態である。またシグナルで(キャンセルボタンやkillコマンドで意図的に)停止されたプロセスは0個(0 stopped)で、ゾンビプロセスは0個。
%Cpu(s) :[各カテゴリごとのプロセス実行時間] us、sy、ni、id、wa、hi、si、stといったカテゴリの、プロセス実行時間割合。各カテゴリは本表中下に記載する。
us ユーザーモードのプロセス
sy カーネルモードのプロセス
ni niceコマンドで優先度を調整された、ユーザーモードのプロセス
wa ディスクへのI/O(読込、書込)を待っているプロセス
hi ハードウェアから割込でタスク実行を依頼され、それに使ったCPUの処理時間
si ソフトウェアから割込でタスク実行を依頼され、それに使ったカーネルの処理時間
st Linuxを仮想化して使っている場合のみ関係のある指標。 ホストOSの物理CPUが複数のゲストOSに共有されている場合の、各ゲストOSがCPUを使うための順番待ちにかかった時間
KiB Mem 物理メモリ
Mib Swap スワップメモリ。スワップメモリとは、ハードディスクドライバの一部領域で、メモリがオーバーしそうな時にそのデータを一時的に退避することが出来る場所のこと。
total 物理メモリ、又はスワップメモリの総量
free 物理メモリ、又はスワップメモリの空き容量
used 物理メモリ、又はスワップメモリのOSやアプリケーションに割当中の容量
buff/cache 物理メモリの、バッファやキャッシュに割当中の容量
avail Mem 物理メモリの実質的な空き容量

そして、下段の各項目の意味は下表のとおりです。

項目 内容
PID プロセスID
USER ユーザー名
PR プロセス優先度
NI プロセス優先度
VIRT 仮想メモリ確保サイズ(KB)
RES 実メモリ使用サイズ(KB)
SHR 共有メモリサイズ(KB)
S 以下のプロセス状態のどれかを表示
R:稼働
S:スリープ
D:スリープ(使用不可)
T:シグナルで停止
Z:ゾンビ
%CPU CPU使用率
%MEM メモリ使用率
TIME+ プロセス稼働時間
COMMAND プロセス名

このようにtopコマンドを使えば、リアルタイムでプロセスの状態を確認することができます。

ps

psコマンドでは、現在実行されているプロセスを確認することができます。基本書式は以下のとおりです。

ps <オプション>

指定できる主なオプションは以下です。

オプション 詳細
-e 全てのプロセスを表示。-Aとしても同じ結果が出力される。
a 実行しているユーザーの全てのプロセスを表示
u CPUやメモリなどを詳細表示
x 端末操作以外のプロセス(デーモンと呼ばれる。TTYの項目が「?」となる)を表示

まずはオプションを指定せずに以下を実行してください。

 $ ps 
  PID TTY          TIME CMD
 1276 tty/1    00:00:00 bash
 2677 tty/1    00:00:00 ps

表示された各項目の詳細は以下になります。

項目 詳細
PID プロセスID
TTY プロセス制御端末。どのターミナルから実行されたプロセスであるかを表す。
TIME プロセスの実行時間
CMD 実行中のコマンド名

次に、uオプションを付けて実行してみます。 この場合、オプションを指定しない場合よりも詳細な情報が出力されます。

 $ ps u
 USER       PID  %CPU  %MEM     VSZ   RSS   TTY    STAT  START   TIME  COMMAND
 vboxuser  1276   0.0   0.2  115812  2508  tty1    Ss    15:03   0:00  -bash
 vboxuser  3730   0.0   0.1  155448  1840  tty1    R+    18:34   0:00  ps u

新しく出力された項目の意味は下表のとおりとなります。

項目 詳細
%CPU CPUの占有率
%MEM メモリーの占有率
VSZ スワップメモリーを含めたメモリサイズ
RSS メモリー上で使用しているサイズ
STAT プロセスの状態。「R」は稼働中、「+」はフォアグラウンドジョブ、「S」はスリープ中、「s」はセッションリーダーを意味する。
START プロセスの開始時間
COMMAND 実行中のコマンド名

psコマンドは、auxとオプションを三つまとめて実行されることが良くあります。 これは、全てのプロセスを詳細情報含めて表示します。出力件数が多くなるので、以下のようにパイプラインでlessコマンドと繋げて実行してください。

 $ ps aux | less
 USER       PID  %CPU  %MEM     VSZ   RSS   TTY    STAT  START   TIME  COMMAND
 root         1   0.0   0.6  128012  6636     ?    Ss    15:03   0:01  /usr/lib/systemd/systemd  --switched-root --system --deserialize 22
 root         2   0.0   0.0       0     0     ?    S     15:03   0:00  [kthreadd]
 root         4   0.0   0.0       0     0     ?    S                                     ・
 
                                    <中略>
 
 
 vboxuser  1276   0.0   0.2  115812  2508  tty1    Ss    15:03   0:00  -bash
 vboxuser  3730   0.0   0.1  155448  1840  tty1    R+    18:34   0:00  ps u

沢山の情報が出力されていると思いますので、「j」ボタンで下にスクロール、「k」ボタンで上にスクロールして出力結果をご確認ください。 よく見ると、CPUとメモリーの使用量が0.0となっているものが多くあることに気づくかと思います。 これは、実行中のプロセスの多くが、外部からのイベント発生を待つ、待機中の状態となっている為です。

jobs

jobsコマンドでは、実行・停止中のジョブを一覧で表示することができます。 基本書式と指定できる主なオプションは以下のとおりとなります。

jobs <オプション>
オプション 詳細
-l プロセスIDも付加して表示する
-p プロセスIDのみ表示する
-r 実行中のジョブのみ表示する
-s 停止中のジョブのみ表示する

jobsコマンドを試すために、vimコマンドを実行して[ctrl + z]を押してください。 [ctrl + z]はジョブを一時停止状態(終了ではない)にする操作です。

その後、以下のようにjobsコマンドを実行してください。停止中となっているvimに関するジョブ表示されました。 [1]と表示されているのは、このvimのジョブIDが「1」であることを意味しています。

 $ jobs
 [1]+ Stopped      vim

bg

次に「bg」コマンドを使って、今停止中となっているvimのジョブをバックグラウンドに移行しましょう。 基本書式は以下のとおりとなります。

bg % <ジョブID>

先ほどjobsコマンドを実行したときに、vimのジョブIDが「1」であることが分かっています。従って、上記書式で「%1」とすれば、vimのジョブをバックグラウンドに移行できます。 以下のとおり実行してください。

 $ bg %1 

これでvimのジョブがバックグラウンドで実行されました。

fg

最後に、現在バックグラウンドで実行されているvimのジョブを、ユーザーが操作できるよう、フォアグラウンドに移行しましょう。 フォアグラウンドに移行するには「fg」コマンドを使います。書式は以下のとおりです。

fg % <ジョブID>

以下を実行してください。先ほどのコマンドの実行結果から、vimのジョブIDが「1」であると分かったので、%1として、操作対象のジョブを指定しています。 実行すると、今までバックグラウンドで実行されていたvimのジョブがフォアグラウンド並行し、テキスト編集画面が再度起動します。

 $ fg %1

kill

以上でプロセスやジョブを操作するコマンドの紹介が完了しました。 最後に、プロセスやジョブを削除するkillコマンドを紹介します。 killコマンドの書式は以下になります。

 kill -<シグナル名またはシグナルID> {<プロセスID> or %<ジョブID>}

まず準備としてtopコマンドをバックグラウンドで実行します。

 $ top &
 [2] 3017

「プロセスIDが3017、ジョブIDが2」 となっているようです。念のために、下記コマンドを実行して確認をします。

 $ top &
 $ jobs
 [2]- Stopped
 $ pidof top
 3017

このような場合、killコマンドでプロセスを削除するには以下のように実行します。

kill 3017

プロセスではなくジョブを削除する場合は、以下のように「%」の後にジョブIDを指定して実行します。

kill %2

これで、不要なプロセスやジョブを削除することが出来るようになりました。

終わりに

以上でLesson9を終了します。 本レッスンではプログラムの実行から終了までという観点で、プロセスやジョブの状態を管理する方法を学びました。 次回のレッスンでは、パッケージ管理ツールについて学習を行います。