Linuxのコンテキストスイッチを徹底解説|仕組み・発生原因・確認方法コンテキストスイッチ

はじめに

Linuxでは、多数のプロセスやスレッドが動作しているため、CPUで実行するタスクを切り替えながら処理しています。

タスクを切り替える際には、後から処理を再開できるように、CPUレジスタやプログラムカウンタなどの実行状態を保存し、次に実行するタスクの状態を復元します。この処理を「コンテキストスイッチ(Context Switch)」と呼びます。

コンテキストスイッチはCPUを複数のタスクで共有するために必要ですが、状態の保存・復元などによるオーバーヘッドも発生します。そのため、CPUパフォーマンスを分析するうえでも重要な仕組みです。

本記事では、コンテキストスイッチの仕組みや発生するタイミング、パフォーマンスへの影響、Linuxでの確認方法について解説します。

コンテキストスイッチとは

コンテキストスイッチとは、CPUで実行するタスクを、現在実行中のタスクから別のタスクへ切り替える処理です。

Linuxでは多数のプロセスやスレッドが動作していますが、1つのCPUコアがある瞬間に実行できるタスクは基本的に1つです。そのため、複数のタスクでCPUを共有するには、実行するタスクを切り替える必要があります。

代表的なコンテキストスイッチ発生のケースは次のとおりです。

・I/O待ちなどによってタスクがCPUを手放した
・sleepやロック待ちによってタスクが待機した
・スケジューラによって別のタスクが選択された

例えば、CPUでタスクAを実行している途中で、CPUスケジューラが次にタスクBを実行すると判断した場合を考えてみます。大まかな流れは次のようになります。

ここで重要なのが、「実行状態を保存・復元する」という処理です。

コンテキストとは

コンテキストとは、タスクがCPUで処理を続けるために必要となる実行状態のことです。代表的なものには、CPUレジスタ、プログラムカウンタ、スタックポインタなどがあります。

例えば、タスクAがCPUで計算処理を行っている途中でタスクBへ切り替わったとします。このときタスクAの実行状態を保存せずに切り替えてしまうと、再びタスクAへCPUが割り当てられたときに「どの命令から処理を再開すればよいのか」「レジスタにどの値が入っていたのか」が分からなくなってしまいます。そこでLinuxカーネルは、タスクAの実行に必要な状態を保存してから、タスクBの状態を復元します。

その後、再びタスクAがCPUで実行されることになれば、保存していた状態を復元することで、以前中断したところから処理を再開できます。

CPUスケジューラとの関係

CPUスケジューラとコンテキストスイッチは密接に関係しています。CPUスケジューラは、実行可能なタスクの中から「次にどのタスクをCPUで実行するか」を選択します。

一方、コンテキストスイッチは、スケジューラによって実行対象が変更された際に、実際にCPUの実行対象を切り替えるための処理です。つまり、単純化すると以下の通りです。

CPUスケジューラ: 次に実行するタスクを選択する
コンテキストスイッチ:現在のタスクから次のタスクへ実行を切り替える

このような仕組みによって、CPUコアの数より多くのタスクが存在する環境でも、それぞれのタスクを切り替えながら処理を進めることができます。

Voluntary / Involuntary Context Switch

コンテキストスイッチは、発生する理由によって「Voluntary Context Switch」と「Involuntary Context Switch」の2種類に分けられます。

この違いを理解しておくと、コンテキストスイッチが増加したときの原因を分析しやすくなります。

Voluntary Context Switch

Voluntary Context Switch(自発的コンテキストスイッチ)は、実行中のタスクが自らCPUを手放すことで発生します。代表的なのは、I/O待ちやsleep、ロック待ちなどです。

例えば、タスクがストレージからデータを読み込み、その完了を待つ場合、その間はCPUで処理を続けることができません。そのため、タスクはCPUを手放して待機し、別のタスクがCPUで実行されます。

タスクAを実行

I/O待ちが発生

タスクAがCPUを手放す

タスクBへ切り替え

このように、タスク側の都合でCPUを手放した場合がVoluntary Context Switchです。

Involuntary Context Switch

Involuntary Context Switch(非自発的コンテキストスイッチ)は、実行中のタスクが自らCPUを手放したのではなく、スケジューラによって別のタスクへ切り替えられた場合に発生します。

例えば、タスクAを実行している途中で、スケジューラが別のタスクを実行すべきだと判断すると、タスクAの実行を中断して別のタスクへCPUを割り当てることがあります。

タスクAを実行

スケジューラが切り替えを判断

タスクAの実行を中断

タスクBへ切り替え

このように、スケジューラによって実行中のタスクがCPUを手放す場合がInvoluntary Context Switchです。

Voluntary / Involuntary Context Switchの違いのまとめ

違いを簡単に整理すると、次のようになります。

種類主な原因
VoluntaryI/O待ち、sleep、ロック待ちなど
Involuntaryスケジューラによるプリエンプションなど

つまり、「自分からCPUを手放したか」「スケジューラによってCPUを手放したか」という違いで考えると分かりやすいです。

図解すると以下の通りです。

コンテキストスイッチのコスト

コンテキストスイッチは、複数のタスクでCPUを共有するために必要な仕組みです。一方で、タスクを切り替える際には、現在のタスクの実行状態を保存し、次のタスクの状態を復元する必要があるため、一定のオーバーヘッドが発生します。

実行状態の保存・復元

コンテキストスイッチでは、CPUレジスタやプログラムカウンタ、スタックポインタなどの実行状態を保存・復元します。

この処理自体にCPU時間が必要となるため、コンテキストスイッチが頻繁に発生すると、その分だけ本来のアプリケーション処理に使えるCPU時間が減る可能性があります。

CPUキャッシュへの影響

タスクが切り替わると、次に実行するタスクが必要とする命令やデータがCPUキャッシュに存在しない場合があります。その場合、メモリからデータを読み込む必要があるため、処理速度が低下する可能性があります。

つまり、コンテキストスイッチのコストは、実行状態の保存・復元だけではなく、CPUキャッシュの利用効率にも影響します。

Linuxでコンテキストスイッチを確認する

Linuxでは、コンテキストスイッチの発生状況をさまざまなコマンドや/proc配下の情報から確認できます。

システム全体のコンテキストスイッチを確認する方法と、特定のプロセスで発生しているコンテキストスイッチを確認する方法があります。

ここでは、代表的な確認方法を紹介します。

vmstatでシステム全体を確認する

システム全体のコンテキストスイッチを簡単に確認するには、vmstatコマンドを利用できます。例えば、1秒間隔で確認する場合は次のように実行します。

[root@almalinux ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 2266664  11216 287904    0    0     5    20    0    0  0  0 99  0  0
 0  0      0 2266664  11216 287904    0    0     0     0  697 1143  0  0 100  0  0
 0  0      0 2266664  11216 288036    0    0     0     0  676 1159  0  0 99  0  0
 0  0      0 2266664  11216 288036    0    0     0     8  656 1147  0  0 99  0  0
 0  0      0 2265656  11224 288036    0    0     0    16  806 1234  1  1 99  0  0

コンテキストスイッチを確認する場合は、systemのcsに注目します。csは、1秒あたりに発生したコンテキストスイッチの回数を表します。上記の例では、1秒間に約1,100~1,200回のコンテキストスイッチが発生していることが分かります。

また、vmstatではRun Queueの状況を示すrやCPU使用率も同時に確認できます。そのため、「コンテキストスイッチが増えている」だけではなく、「Runnableなタスクも増えている」、「CPU使用率も高くなっている」といった情報を組み合わせて確認できます。

pidstatでプロセスごとに確認する

どのプロセスでコンテキストスイッチが発生しているのかを確認したい場合は、pidstatコマンドが便利です。次のように実行します。-wを指定すると、プロセスごとのコンテキストスイッチを確認できます。

[root@almalinux ~]# pidstat -w 1
Linux 5.14.0-570.19.1.el9_6.x86_64 (almalinux)  08/10/2026      _x86_64_        (4 CPU)

10:52:03 PM   UID       PID   cswch/s nvcswch/s  Command
10:52:04 PM     0        16      1.00      0.00  ksoftirqd/0
10:52:04 PM     0        17     11.00      0.00  rcu_preempt
10:52:04 PM     0       418      3.00      1.00  jbd2/sda3-8
10:52:04 PM     0    845637      1.00      0.00  httpd
10:52:04 PM     0   3189679    132.00      0.00  kworker/u16:1-events_unbound
10:52:04 PM     0   3189814      1.00      0.00  kworker/0:2-mm_percpu_wq
10:52:04 PM     0   3189918      2.00      0.00  kworker/2:0-events_power_efficient
10:52:04 PM  1000   3189938      2.00      0.00  sshd

代表的な項目は次の2つです。

項目意味
cswch/s1秒あたりのVoluntary Context Switch
nvcswch/s1秒あたりのInvoluntary Context Switch

例えばcswch/sが多い場合は、I/O待ちやsleep、ロック待ちなどによってタスクがCPUを手放している可能性があります。上記の例では、表示されているすべてのタスクでcswch/sが0より大きいため、Voluntary Context Switchが発生していることが分かります。

一方、nvcswch/sが多い場合は、スケジューラによるプリエンプションが多く発生している可能性があります。上記の例では、「jbd2/sda3-8」のnvcswch/sが1.00となっているため、1秒あたり約1回のInvoluntary Context Switchが発生していることが分かります。

vmstatでシステム全体のcsが増えていることを確認したあと、pidstatでどのプロセスが多くのコンテキストスイッチを発生させているのか調査すると分かりやすいでしょう。

/proc/PID/statusで確認する

特定のプロセスについては、/proc/PID/statusからもコンテキストスイッチの回数を確認できます。

[root@almalinux ~]# cat /proc/357466/status
~~Truncated~~

voluntary_ctxt_switches:        1467756
nonvoluntary_ctxt_switches:     849
[root@almalinux ~]#

出力の中には、次のような項目があります。

voluntary_ctxt_switches : Voluntary Context Switchの累積回数
nonvoluntary_ctxt_switches : Involuntary Context Switchの累積回数

pidstatが一定時間あたりの発生回数を確認するのに向いているのに対して、/proc/PID/statusではそのタスクについて蓄積された回数を確認できます。

/proc/PID/schedで確認する

CPUスケジューリングに関する情報をさらに詳しく確認したい場合は、/proc/PID/schedを利用できます。

[root@almalinux ~]# cat /proc/357466/sched
postmaster (357466, #threads: 1)
-------------------------------------------------------------------
se.exec_start                                :   20292058479.997639
se.vruntime                                  :       1993325.511545
se.sum_exec_runtime                          :       1115646.811401
se.nr_migrations                             :               241860
nr_switches                                  :              1468623
nr_voluntary_switches                        :              1467774
nr_involuntary_switches                      :                  849

代表的な項目として、次の3つがあります。

nr_switches:コンテキストスイッチの合計
nr_voluntary_switches:Voluntary Context Switchの回数
nr_involuntary_switches: Involuntary Context Switchの回数

合わせて、CPUスケジューリングに関する下記の情報を確認することできます。

se.vruntime:タスクのCPU実行時間を重み付けした仮想的な実行時間
se.sum_exec_runtime:実際にCPU上で実行された累積時間
se.nr_migrations:タスクが別のCPUへ移動した回数

目的によって確認方法を使い分ける

コンテキストスイッチを調査するときは、1つのコマンドだけを見るのではなく、目的に応じて使い分けることが重要です。

・システム全体を見る:vmstat
・プロセスごとの発生頻度を見る:pidstat -w
・特定タスクの累積回数を見る:/proc/PID/status
・スケジューリング情報と合わせて詳しく見る:/proc/PID/sched

特にパフォーマンス調査では、まずvmstatでシステム全体の傾向を確認し、コンテキストスイッチが多い場合にpidstatなどで原因となっているプロセスを絞り込む方法が分かりやすいでしょう。

ただし、コンテキストスイッチの回数が多いだけで、性能問題と判断することはできません。

次の章では、コンテキストスイッチが多い場合に、どのような観点で原因を調査すればよいのかを見ていきます。

コンテキストスイッチが多いときの見方

Linuxのパフォーマンスを調査していると、vmstatやpidstatで大量のコンテキストスイッチが発生していることがあります。しかし、コンテキストスイッチが多いからといって、それだけで性能問題が発生しているとは判断できません。

Webサーバやデータベースなど、多数のプロセスやスレッドが動作するシステムでは、コンテキストスイッチが多く発生すること自体は珍しくありません。重要なのは、コンテキストスイッチの回数だけではなく、CPU使用率やRun Queueなどの情報と組み合わせて確認することです。

CPU使用率と合わせて確認する

まず確認したいのがCPU使用率です。コンテキストスイッチが多くてもCPUに余裕があり、アプリケーションの性能にも問題がなければ、必ずしも対処する必要はありません。

一方で、以下のような状況では、多数のタスクがCPUを奪い合い、頻繁な切り替えが発生している可能性があります。

・コンテキストスイッチが多い
・CPU使用率も高い
・アプリケーションのレスポンスも悪化している

vmstatでは、csとCPU使用率を同時に確認できるため、システム全体の傾向を確認するのに便利です。

Run Queueと合わせて確認する

CPU上で実行可能なタスクが多い場合、複数のタスクがCPUで実行される機会を待つことになります。vmstatのrでは、CPUで実行中またはCPUで実行されるのを待っているRunnableなタスク数を確認できます。

例えば、CPU使用率が高い+ rが継続的に多い+コンテキストスイッチも多い、という場合、多数のタスクがCPUを競合している可能性があります。

特に、rがCPUコア数を継続的に大きく上回っている場合は、CPUがボトルネックになっていないか確認するとよいでしょう。

VoluntaryとInvoluntaryを確認する

コンテキストスイッチが多い場合は、VoluntaryとInvoluntaryのどちらが多いのかを確認することも重要です。

Voluntary Context Switchが多い場合は、I/O待ちやロック待ち、sleepなどによって、タスクが自らCPUを手放している可能性があります。

一方、Involuntary Context Switchが多い場合は、多数のRunnableなタスクが存在し、スケジューラによるプリエンプションが頻繁に発生している可能性があります。

pidstat -wを利用すると、プロセスごとに両者を確認できます。

プロセスやスレッド数を確認する

コンテキストスイッチが増える原因の一つとして、プロセスやスレッド数の増加があります。

例えば、CPUコア数に対して非常に多くのスレッドを作成すると、同時に実行可能なスレッドが増え、CPUでの実行対象が頻繁に切り替わる可能性があります。

そのため、コンテキストスイッチが急増した場合は、

・プロセス数が増えていないか
・スレッド数が増えていないか
・特定のプロセスでcswch/sやnvcswch/sが増えていないか

といった点も確認します。

コンテキストスイッチ数だけで判断しない

コンテキストスイッチには、「1秒間に何回を超えたら異常」といった共通の基準があるわけではありません。システムのCPUコア数、ワークロード、プロセスやスレッドの数などによって、正常な値は大きく異なります。

そのため、以下の情報を組み合わせて判断することが重要です。

・コンテキストスイッチ数
・CPU使用率
・Run Queue
・Voluntary / Involuntary
・アプリケーションのレスポンス

また、通常時の値を継続的に取得しておけば、障害発生時に「普段と比べてコンテキストスイッチが急増している」といった変化にも気付きやすくなります。

コンテキストスイッチは単独で性能問題を判断する指標ではなく、CPUで何が起きているのかを理解するための一つの手掛かりとして利用するとよいでしょう。

まとめ

本記事では、Linuxにおけるコンテキストスイッチの仕組みについて解説しました。

Linuxでは、多数のプロセスやスレッドでCPUを共有するために、CPUで実行するタスクを切り替えながら処理を進めています。この実行対象を切り替えるために必要となるのがコンテキストスイッチです。

コンテキストスイッチでは、現在のタスクのCPUレジスタやプログラムカウンタ、スタックポインタなどの実行状態を保存し、次に実行するタスクの状態を復元します。これによって、それぞれのタスクはCPUを一度手放した後でも、中断したところから処理を再開できます。

また、コンテキストスイッチは発生理由によって、大きく次の2種類に分けられます。

Voluntary Context Switch
→ I/O待ちやsleep、ロック待ちなどによってタスクがCPUを手放す

Involuntary Context Switch
→ プリエンプションなどによってスケジューラが実行タスクを切り替える

コンテキストスイッチはLinuxが複数のタスクを効率よく実行するために必要な仕組みですが、実行状態の保存・復元やCPUキャッシュなどへの影響によって一定のオーバーヘッドも発生します。

そのため、パフォーマンスを調査するときは、コンテキストスイッチ数だけで問題を判断するのではなく、CPU使用率やRun Queue、Voluntary / Involuntary Context Switchなどと組み合わせて確認することが重要です。

Linuxでは、vmstat、pidstat、/proc/PID/status、/proc/PID/schedなどを利用することで、実際のコンテキストスイッチの発生状況を確認できます。

コンテキストスイッチの仕組みを理解しておくことで、「なぜ多数のタスクが少ないCPUを共有できるのか」だけでなく、CPU高負荷時にLinux内部で何が起きているのかも理解しやすくなります。

LinuxにおけるCPUの仕組みについては、以下の書籍にまとめています。興味がありましたら、ぜひ読んでみてください。

Linux入門・図解

LinuxのCPUの仕組みを
図解で理解したい方へ

命令実行・プロセス・スケジューラ・割り込み・ キャッシュ・マルチコアなど、 LinuxにおけるCPUの仕組みを図解を中心にわかりやすく解説しています。

Kindleで書籍を見る →

コメント