OS

目次

概要

初心者から大学院レベルまでの包括的解説

現代のコンピュータシステムは、アプリケーションからクラウドインフラ、モバイル端末、IoTまでのすべてがOSの上に成り立っています。この章では、OSの理論・実装・歴史・最新動向を体系的に整理します。

要点

この章は、OSを「プロセス・メモリ・ファイル・I/O・ネットワークをどう安全かつ効率よく共有するか」という視点で理解するための全体地図です。定義や理論だけでなく、Linuxを軸に実装や観察のしかたまでつなげます。

この章の対象

この章は次の読者を想定しています。

  • 初心者向け: OSの基本概念から学びたい方
  • 開発者向け: システムプログラミング・パフォーマンス改善に取り組む方
  • インフラ/SRE向け: Linuxカーネルコンテナ・クラウドを深く理解したい方
  • 研究者・学生向け: OS設計の理論的基盤を押さえたい方

OSとは何か

オペレーティングシステム(Operating System, OS) は、コンピュータのハードウェアとソフトウェアの資源を管理し、プログラムが実行するための共通サービスを提供するシステムソフトウェアである。OSの本質は以下の三つの側面に凝縮される。

  1. リソース管理者(Resource Manager)CPU、メモリ、ディスク、ネットワーク、周辺機器を公平かつ効率的に配分する。
  2. ハードウェア抽象化層(Hardware Abstraction Layer) — 多様なハードウェアの違いを隠蔽し、統一的なインターフェースを提供する。
  3. 仮想マシン提供者(Virtual Machine Provider) — 各プロセスに「自分専用のコンピュータ」という幻想を与え、保護・分離を実現する。

キーコンセプト: OSは「ユーザーと機械の仲介者」であり、同時に「ハードウェアの複雑性を隠蔽するレイヤー」であり、さらに「各プロセスに独立した仮想世界を提供するハイパーバイザ的存在」でもある。これら三つの役割を統合的に担う点が、OSを他のソフトウェアから際立たせる。

現代のOSは単なる「PCを動かす土台」にとどまらず、クラウド、コンテナ、モバイル、組み込み、リアルタイム制御、さらにはAI推論基盤に至るまで、情報社会の根幹を支える巨大な技術スタックである。Linuxカーネルも、数千万行規模のコードと多数の開発者による長年の分散開発の上に成り立つ、世界最大級のオープンソース基盤の一つである。


OSの定義と哲学

ヒント

OSとは何かを「教科書的定義」と「実用上の役割」の両方から把握する章です。ここでは「リソース管理者」「ハードウェア抽象化層」「仮想マシン提供者」の3つの視点でOSを捉えます。

形式的定義

SilberschatzはOSを次のように定義している:

“An operating system is a program that manages the computer hardware. It also provides a basis for application programs and acts as an intermediary between the computer user and the computer hardware.”

Tanenbaumはよりプラグマティックに、OSを「拡張機械(Extended Machine)」と「リソース管理者(Resource Manager)」の二重の観点から定義する。

  • 拡張機械としてのOS:生のハードウェア(レジスタ、割り込み、DMA、ディスクジオメトリ)は複雑で危険なため、OSはこれらを抽象化し、プログラマが扱いやすい「仮想計算機」を提供する。read(fd,buf,n)read(fd, buf, n) というシステムコールは、内部的にはセクタ計算、キャッシュ参照、DMA設定、割り込み待機を経て実行されるが、プログラマからは単なる関数呼び出しに見える。
  • リソース管理者としてのOS:複数の競合するプロセスがCPU、メモリ、I/Oを共有する際、公平性・効率・保護を担保するのがOSの責務である。

三位一体の役割

graph TB A["オペレーティングシステム"] B["リソース管理者"] C["ハードウェア抽象化層"] D["仮想マシン提供者"] A --> B A --> C A --> D B --> B1["CPU時間の配分(スケジューリング)"] B --> B2["メモリ割り当て(仮想メモリ・ページング)"] B --> B3["ディスク/ストレージ管理(ファイルシステム)"] B --> B4["I/O制御(デバイスドライバ、割り込み)"] B --> B5["ネットワーク帯域制御(QoS)"] C --> C1["複雑さの隠蔽(システムコール)"] C --> C2["統一インターフェース(POSIX、Win32)"] C --> C3["ポータビリティ(HAL、KMI)"] D --> D1["独立した仮想アドレス空間"] D --> D2["プロセス間の隔離と保護"] D --> D3["時分割による並行性の幻想"]

OSの設計哲学

UNIX哲学は現代OSの根幹を形作っている:

  1. Do one thing and do it well — ツールは一つのことを上手にやる。
  2. Write programs to work together — プログラムは協働できるよう設計する(パイプ)。
  3. Handle text streams as universal interface — テキストストリームをユニバーサルなインターフェースとする。
  4. Everything is a file — すべてはファイルである(デバイス、ソケットプロセス情報まで)。

この哲学はLinuxmacOS (XNU/Darwin)、BSD系、さらにはAndroidにまで受け継がれている。一方WindowsはCOM/OLE/NT Object Managerに代表される「すべてはオブジェクトである」という異なる抽象を採用している。

なぜOSが必要か — 歴史的動機

1950年代、初期コンピュータ(ENIAC、EDSAC)にはOSが存在しなかった。プログラムはバイナリとして直接ロードされ、プログラマがハードウェアを手作業で制御した。1960年代にバッチ処理システム(FMS, IBSYS)が登場し、1969年のUnix誕生で「マルチユーザー・マルチタスキング・階層ファイルシステム」が一般化した。OSが必要とされたのは以下の技術的圧力による:

  • ハードウェア利用率:人間のオペレータが磁気テープを装填していた時代、CPU利用率は1% 未満だった。バッチ処理とスプーリングでこれを劇的に改善する必要があった。
  • 多重プログラミング:I/O待ち中にCPUが遊ぶのを避けるため、複数プログラムを同時にメモリに載せる仕組みが必要となった。
  • 保護:共有環境で一つのプログラムが他を破壊しないよう、ハードウェアとソフトウェアによる保護機構が必要となった。
  • 利便性:パンチカードや磁気テープの直接操作は誤りが多く、ファイル・ディレクトリといった抽象が不可欠だった。

OSの主要機能

ヒント

OSが提供する機能は10以上ありますが、「プロセス」「メモリ」「ファイル」「I/O」「ネットワーク」の5つを押さえればほぼ全体像が見えます。

1. プロセス管理(Process Management)

OSプロセスの生成・終了・状態遷移・スケジューリング・プロセス間通信を管理する。Linuxでは fork()exec()wait()exit() という古典的なUNIX APIに加え、clone()posixspawn()posix_spawn()vfork()、さらに名前空間を扱う unshare()setns() がある。Windowsでは CreateProcess()WaitForSingleObject() など独自APIを用いる。

2. メモリ管理(Memory Management)

仮想メモリシステム、ページング、スワッピング、メモリ保護、共有メモリを担う。現代OSは以下のような階層化されたメモリ管理を行う:

役割 代表的技術
MMU 仮想→物理変換 ページテーブル、TLB、EPT、Intel PML5
カーネル ページ割り当て、回収 バディ、スラブ、SLUB、LRU list
プロセス 仮想アドレス空間管理 VMA (vm_area_struct)、mmap
ランタイム層 ヒープ管理 malloc (ptmalloc2, jemalloc, tcmalloc, mimalloc)

3. ファイルシステム・ストレージ管理

ファイルの作成・読み書き・メタデータ管理・アクセス制御、ディスクスペースの割り当て、ジャーナリング、暗号化、スナップショットなど。LinuxではVFS (Virtual File System) 抽象により、ext4、XFS、Btrfs、ZFS、NFS、FUSEなど多様な実装を統一的に扱う。

4. 入出力管理(I/O Management)

デバイスドライバ、割り込みハンドラ、バッファリング、スプーリング、非同期I/O (AIO, io_uring, IOCP)、DMAの制御。ここで スプーリング は「すぐ処理できない入出力要求をいったんキューにためること」、DMA は「CPUを介さずにデバイスがメモリへ直接読み書きすること」を指す。Linuxカーネルではblock layer、net layer、char deviceという区分でドライバが組織化される。

5. ネットワーキング

TCP/IPスタック、ソケットAPI、ルーティング、パケットフィルタリング(Netfilter, eBPF, pf)、QoS、仮想ネットワーク(VLAN, VXLAN, overlay)。ここで VLAN は1本の物理ネットワークを論理的に分割する仕組み、VXLAN はその仮想ネットワークをIP網の上にトンネルとして重ねる仕組みである。LinuxNetfilterカーネル内パケットフィルタ基盤で、iptablesnftables はその上でルールを定義するための仕組みである。

6. セキュリティと保護

認証(PAM, Kerberos)、認可(DAC, MAC, RBAC, ABAC)、監査(auditd, ETW)、暗号化(dm-crypt, BitLocker, FileVault, APFS encryption)、サンドボックス(seccomp, AppArmor, SELinux, Windows AppContainer)。認可方式のうち DAC は所有者が権限を決める方式、MACOS側の強制ルールで制御する方式、RBAC は役割ベース、ABAC は属性ベースの制御である。

7. ユーザーインターフェース

CLI(bash, zsh, fish, PowerShell, cmd)、GUI(X11, Wayland, Quartz Compositor, Windows DWM)、API(POSIX, Win32, Cocoa/UIKit)という三層のインターフェースを提供する。たとえば WaylandLinux系の新しい表示プロトコル、Quartz CompositormacOSの画面合成基盤、DWMWindowsのDesktop Window Managerである。

8. 時刻管理とタイマ

クロックソース(TSC, HPET, ACPI PM Timer, ARM Generic Timer)、タイマ(hrtimer, timerfd, CreateTimerQueue)、NTP同期、タイムゾーン、うるう秒処理。ここで TSC はCPU内部の高速カウンタ、HPET は高精度イベントタイマで、OSは用途に応じて使い分ける。RTOSではナノ秒オーダーの確定的タイマが要求される。

9. 電源管理

ACPI(Advanced Configuration and Power Interface)、CPU周波数スケーリング(cpufreq, Intel P-state)、サスペンド/ハイバーネーション(S3/S4)、モバイルOSでのDozeモード、iOS Background App Refresh制御など。ACPI は電源管理やデバイス構成をOSとファームウェアの間で受け渡す標準仕様で、Intel P-state はCPUの性能状態を細かく調整する仕組みである。

10. エラーハンドリング・ログ・診断

例外処理、パニック/BSoD、クラッシュダンプ、カーネルログ(dmesg, journald, Event Viewer, Console.app)、トレーシング(ftrace, eBPF, DTrace, ETW, os_log)、プロファイリング(perf, Instruments, WPA)。


OSのアーキテクチャ

ヒント

「モノリシック」「マイクロカーネル」「ハイブリッド」の3つが主要パターンです。Linuxはモノリシック、macOS/Windowsはハイブリッドという程度を押さえれば十分です。

OSカーネルの設計は歴史上、複数の異なる哲学のもとで発展してきました。性能・信頼性・保守性・セキュリティのトレードオフが異なります。

1. モノリシックカーネル(Monolithic Kernel)

すべてのOSサービス(メモリ管理プロセス管理、ファイルシステム、デバイスドライバ、ネットワーク)が単一のアドレス空間で特権モード実行される。

【図1】モノリシックカーネルの構造:

graph TB Apps["ユーザアプリケーション"] subgraph Kernel["モノリシックカーネル(全機能が単一アドレス空間)"] PM["プロセス管理"] MM["メモリ管理"] FS["ファイルシステム"] DD["デバイスドライバ"] NS["ネットワークスタック"] IH["割り込みハンドラ"] IPC["IPC"] CR["暗号化"] end HW["ハードウェア"] Apps -.システムコール.-> Kernel Kernel -.関数コール・直接参照.-> HW

長所:

  • 関数呼び出しで全機能にアクセス可能 → 極めて高速
  • キャッシュ効率が良い
  • 実装が単純明快(大まかには)

短所:

  • 一つのバグ(NULLポインタ参照、メモリ破壊)がカーネル全体をクラッシュさせる
  • デバイスドライバはカーネル空間で動くため、品質の悪いドライバが致命的
  • コード量が増すと保守が困難(Linuxは既に3,000万行超)

代表例: Linux、FreeBSD、OpenBSD、NetBSD、クラシックUnix、MS-DOS

Linuxは厳密にはモノリシックだが、**ローダブルカーネルモジュール(LKM)**による動的拡張をサポートし、モジュラモノリシック(modular monolithic)と呼ばれる。LKMは「あとから差し込めるカーネル部品」のようなもので、起動時に必要最低限のカーネルしかメモリに置かず、modprobe で実行時にドライバをロードする。

2. マイクロカーネル(Microkernel)

カーネルは最小限の機能(IPCスレッド管理、基本的メモリ管理、タイマ)のみを実装し、ファイルシステム・ネットワーク・デバイスドライバはユーザースペースの サーバプロセス として実行する。IPC(Inter-Process Communication)プロセス間通信のことで、メッセージ送受信や共有メモリなどを通じて別プロセス同士が連携する仕組みを指す。

【図2】マイクロカーネル構造:

この図では、「特権の小さいマイクロカーネル」と「ユーザ空間のサーバ群」がIPCでつながる、という分離のしかたを見る。

graph TB subgraph UserSpace["ユーザースペース(特権なし)"] FS["ファイルサーバ"] Net["ネットワークサーバ"] DD["デバイスドライバ"] App["アプリプロセス"] end subgraph Micro["マイクロカーネル(最小限の特権)"] IPC["IPC / メッセージパッシング"] SM["スレッド・アドレス空間プリミティブ"] IR["ハードウェア割り込みルーティング"] end HW["ハードウェア"] FS <-.IPC.-> IPC Net <-.IPC.-> IPC DD <-.IPC.-> IPC App <-.IPC.-> IPC Micro --> HW

長所:

  • 信頼性:一つのサーバが落ちても他は生存し、再起動で復旧可
  • セキュリティ:特権コードが小さく監査しやすい(seL4は形式検証済み)
  • モジュール性:サーバを独立して開発・交換可能
  • マルチサーバ・分散化との親和性

短所:

  • IPCオーバーヘッド:関数呼び出しがメッセージ送受信になり、コンテキストスイッチが頻発
  • 初期のマイクロカーネル(Mach 2.5)は性能で悪評を得た
  • 単純なファイルI/Oでも複数のコンテキストスイッチが発生

代表例:

  • QNX Neutrino:自動車(CarPlay相互運用、BMW iDrive等)、医療機器
  • Minix 3:Tanenbaumが教育・研究用に開発、Intel ME(Management Engine)にも採用された
  • seL4:C実装と仕様の整合性を大規模に形式検証した、代表的なマイクロカーネル
  • GNU Hurd:長年開発中のGNUマイクロカーネル
  • L4系統(L4, Fiasco, NOVA, Pistachio, OKL4)

3. ハイブリッドカーネル(Hybrid Kernel)

モノリシックとマイクロカーネルの中間。Mach的なIPC・メッセージパッシングをカーネル内部構造として持ちつつ、性能のためファイルシステムやネットワークカーネル空間に取り込む。

代表例:

【図3】XNUの内部構造:

この図では、macOS / iOSのXNUが MachBSDI/O Kit を重ね合わせたハイブリッド構造になっている点を見る。

graph TB subgraph XNU["XNU Kernel"] BSD["BSD層 / POSIX API、プロセス、VFS、ソケット"] Mach["Mach層 / タスク、スレッド、IPC、VM"] IOKit["I/O Kit / C++ ドライバフレームワーク"] LK["libkern / Platform Expert / C++ ランタイム、アーキ固有"] end BSD --- Mach Mach --- IOKit IOKit --- LK

【図4】Windows NTの内部構造:

この図では、WindowsがユーザモードのサブシステムとExecutive群、さらにHALを分けている点に注目すると把握しやすい。

graph TB UM["ユーザモード(サブシステム) / Win32, POSIX, WSL, OS/2(歴代), WinRT / smss.exe, csrss.exe, services.exe, lsass.exe"] EX["Executive(カーネルモード) / Object Manager, Process Manager, Memory Manager / I/O Manager, Security Reference Monitor / Configuration Manager, Cache Manager"] MK["Microkernel (ntoskrnl.exe) / スレッドスケジューリング、割り込み、例外、DPC"] HAL["HAL (Hardware Abstraction Layer)"] HW["ハードウェア"] UM -.NtXxxシステムコール.-> EX EX --> MK MK --> HAL HAL --> HW

4. 層型カーネル(Layered Kernel)

DijkstraのTHE OS (1968) が提唱した設計。各層が下位層のみを呼び出し、逆方向の依存を禁止する。

【図5】層型カーネル(THE OS):

graph TB L5["Layer 5: ユーザープログラム"] L4["Layer 4: I/Oバッファリング"] L3["Layer 3: オペレータコンソールデバイスドライバ"] L2["Layer 2: メモリ管理"] L1["Layer 1: CPUスケジューリング"] L0["Layer 0: ハードウェア"] L5 --> L4 --> L3 --> L2 --> L1 --> L0

教育的価値は高いが、層の厳密な区切りが実装と性能を犠牲にするため、純粋な層型OSは現代では稀。ただし MulticsOS/2 は層型の影響を強く受けた。

5. エクソカーネル(Exokernel)

MITのFrans Kaashoekらが1990年代に提唱。「カーネルは抽象化を提供せず、物理リソースへの保護された直接アクセスのみを提供する」という極端な設計哲学。ファイルシステムやネットワークプロトコルはユーザライブラリ(libOS)として実装される。

意図: アプリケーションが自分に最適な抽象を選べるようにする。DBサーバは専用ファイルシステムlibOSを使い、Webサーバは独自TCPスタックを使える。

代表例: MIT Exokernel(XOK, Aegis, ExOS)、Nemesis(Cambridge)。商用成功には至らなかったが、UnikernelUser-mode drivers、さらには io_uring のゼロコピー設計に思想的影響を残した。

6. ユニカーネル(Unikernel)

アプリケーション・ランタイム・OSカーネルを単一のバイナリにコンパイルし、ハイパーバイザ上で直接動作させる。プロセス分離もユーザ/カーネルモードもない — 一つのアドレス空間に全てが存在する。

代表例: MirageOS(OCaml)、IncludeOS(C++)、HalVM(Haskell)、Rumprun、OSv、Solo5。

利点: 起動時間が短く、攻撃表面が小さく、バイナリサイズやメモリ使用量も抑えやすい。軽量VMやサーバレス実行基盤と設計上の問題意識が近く、特にFirecrackerのようなマイクロVM系の文脈で比較対象として語られることが多い。なお、Cloudflare WorkersはunikernelではなくV8 Isolateベースである。

7. マルチカーネル(Multikernel) / 分散OS

Barrelfish(ETH Zurich × Microsoft Research)は、NUMAやヘテロ構成のメニーコア時代に向けて「コア間で状態を共有せず、メッセージパッシングのみで協調する分散OS」を提案。マルチコア時代のスケーラビリティ課題への応答。

8. アーキテクチャ比較マトリックス

アーキテクチャ 性能 信頼性 保守性 セキュリティ 代表例
モノリシック ★★★★★ ★★ ★★ ★★★ Linux, BSD
マイクロカーネル ★★★ ★★★★★ ★★★★ ★★★★★ QNX, Minix, seL4
ハイブリッド ★★★★ ★★★★ ★★★ ★★★★ Windows NT, XNU
層型 ★★ ★★★ ★★★★ ★★★ THE, Multics
エクソカーネル ★★★★★ ★★★ ★★ ★★★★ XOK, Nemesis
ユニカーネル ★★★★★ ★★★ ★★ ★★★★ MirageOS, IncludeOS

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

現代CPUは少なくとも二つの特権レベル(プロテクションリング)を提供し、OSはこれを利用して自身と他プロセスを保護する。x86-64はRing 0〜Ring 3の4段階を提供するが、実際はRing 0(カーネル)とRing 3(ユーザ)しか使われない。ARMはEL0(ユーザ)〜EL3(Secure Monitor / TrustZone)まで4レベル。RISC-VはM / S / Uモード。

特権レベルの意味

stateDiagram-v2 [*] --> ユーザモード ユーザモード --> カーネルモード: システムコール (syscall/int 0x80) ユーザモード --> カーネルモード: 割り込み (タイマ、I/O) ユーザモード --> カーネルモード: 例外 (ページフォルト、SIGSEGV) カーネルモード --> ユーザモード: sysret / iret note right ofユーザモード: 特権命令禁止 ハードウェアI/O禁止 ページテーブルで制限 note right ofカーネルモード: 全特権命令実行可 全物理メモリアクセス可 直接アクセス可

ユーザモードで禁止される代表的な命令(x86-64):

  • HLT(CPUハルト)
  • CLI/STI(割り込みフラグ制御)
  • IN/OUT(I/Oポート直接アクセス)
  • INVLPG(TLB無効化)
  • LGDT/LIDT(記述子テーブルロード)
  • WRMSR/RDMSR(一部のMSRアクセス)
  • CR0/CR3/CR4 などの制御レジスタへの書き込み

これらを実行しようとするとユーザモードでは一般保護例外(#GP)が発生し、カーネルがSIGILLやSIGSEGVを送出する。

モード遷移のコスト

モード切替(ユーザ→カーネル→ユーザ)は単なるジャンプではなく、レジスタ保存、スタック切替、場合によってはTLBや分岐予測器のフラッシュを伴う。典型的なsyscallのオーバーヘッドは100〜500 ns程度だが、Meltdown/Spectre脆弱性対策(KPTI: Kernel Page-Table Isolation) を有効にすると倍増することがある。

この遷移コストを避ける工夫:

  • vDSO(Virtual Dynamic Shared Object)Linuxgettimeofday()clockgettime()clock_gettime()getcpu() などの頻繁に呼ばれる関数をユーザ空間にマップし、カーネルに遷移せず実行する。
  • io_uring:システムコール境界を跨がない共有リングバッファでI/Oを発行・完了通知する。
  • eBPF:小さなサンドボックスプログラムをカーネル内で実行し、ユーザ空間に戻る頻度を減らす。
  • ユーザ空間ドライバ(DPDK, SPDK):NICやNVMeを直接ユーザ空間にマップし、カーネルを通さずパケット・I/Oを処理する。

システムコールとABI

システムコール(syscall)は、ユーザプログラムがカーネルに処理を依頼するための公式インターフェースである。

Linux x86-64のsyscall規約

x86-64では、Linuxsyscall 命令を使う新しい規約を採用している:

レジスタ 用途
RAX システムコール番号(例:read = 0、write = 1、openat = 257)
RDI 第1引数
RSI 第2引数
RDX 第3引数
R10 第4引数(関数呼び出し規約とは異なるので注意)
R8 第5引数
R9 第6引数
RAX(戻り値) 返り値、負数はエラー(-errno)

例:write(1, "hello\n", 6) を直接syscallで呼ぶx86-64アセンブリ:

    mov rax, 1          ; syscall number: write
    mov rdi, 1          ; fd: stdout
    lea rsi, [rel msg]  ; buf
    mov rdx, 6          ; count
    syscall             ; kernelに制御を移す

msg: db "hello",0x0a

システムコール数

  • Linux 6.x(x86-64):約 450種類
  • FreeBSD 14:約580種類
  • macOS(XNU):数百(BSD syscalls + Mach traps + machine-dependent)
  • Windows NT Native API:約450種類(NtCreateFile など)

Linuxのシステムコール一覧は /usr/include/asm/unistd64.h/usr/include/asm/unistd_64.hman 2 syscalls で確認できる。

POSIXとABI

**POSIX(Portable Operating System Interface)**はIEEEが制定するUnix系OSの標準API。POSIX.1は基本API(fork, exec, open, read, write)を、POSIX.1bはリアルタイム拡張(schedsetschedulersched_setscheduler, shmopenshm_open)を、POSIX.1cはpthreadをカバーする。

ABI(Application Binary Interface)ISAOSごとに異なり、関数呼び出し規約・システムコール規約・構造体レイアウト・実行ファイル形式(ELF, Mach-O, PE)を定める。同じOSでもABIが異なれば実行できない(Linux x86-64Linux ARM64は互換性なし)。

高速呼び出し機構の進化

  1. int 0x80(i386時代)— ソフトウェア割り込み。遅い。
  2. SYSENTER/SYSEXIT(Pentium II、Intel)— 専用命令で高速化。
  3. SYSCALL/SYSRET(AMD64、Intel 64)— 現代のx86-64で標準。
  4. vDSO(上述)— 一部システムコールをユーザ空間で完結。
  5. io_uring(Linux 5.1, 2019)— バッチ化された非同期I/O。

Linuxアーキテクチャの詳細

Linuxは1991年にフィンランドのヘルシンキ大学の学生Linus Torvaldsによって開発開始された。現在のLinuxカーネルは世界最大級のオープンソースプロジェクトであり、おおむね次のような規模感で語られる。

  • ソースコード:数千万行規模
  • コントリビュータ:長期累計で非常に多数
  • リリース頻度:9〜10週間ごと
  • メンテナ:Linus TorvaldsがBDFL、各サブシステムにlieutenants
  • 開発言語:C(主)、アセンブリ、Rust(2022年より部分的に導入)

Linuxシステムの階層

【図6】Linuxシステムの階層構造:

graph TB App["ユーザアプリケーション / Firefox, Vim, Python, Nginx, Docker, etc."] Lib["システムライブラリ / glibc, musl, libstdc++, libssl, libcrypto"] subgraph Kernel["Linuxカーネル"] PM["プロセス管理"] MM["メモリ管理"] VFS["仮想ファイルシステム (VFS)"] NS["ネットワークスタック"] IPC["IPC"] SEC["セキュリティ (LSM)"] DD["デバイスドライバ・カーネルモジュール"] end HW["ハードウェア / CPU, RAM, ディスク, NIC, GPU, 周辺機器"] App -.ライブラリコール.-> Lib Lib -.システムコール.-> Kernel Kernel --> HW

主要サブシステム

1. プロセス・スケジューラ (kernel/sched/)

Linux 2.6.23以降は CFS(Completely Fair Scheduler) が通常プロセスをスケジュールしてきた。CFSは赤黒木で “virtual runtime (vruntime)” をキーにプロセスを順序付け、最小vruntimeを持つプロセスを次に実行する。

Linux 6.6(2023年10月)からは EEVDF(Earliest Eligible Virtual Deadline First)スケジューラCFSを置き換えた。EEVDFはPeter Zijlstra博士らによって実装され、リクエスト遅延の予測可能性を向上させる。

リアルタイムプロセスは SCHEDFIFOSCHED_FIFOSCHEDRRSCHED_RRSCHEDDEADLINESCHED_DEADLINE の各ポリシーで別系統にスケジュールされる。

2. メモリ管理 (mm/)

3. 仮想ファイルシステム (VFS, fs/)

Sun Microsystemsが1985年にNFSのため導入した設計をLinusが採用。struct inodestruct dentrystruct filestructsuperblockstruct super_block が抽象化の核となる。これによりext4、XFS、Btrfs、ZFS、NFS、FUSE、tmpfs、procfs、sysfs、debugfs、cgroupfsが統一APIで利用可能。

4. ネットワークスタック (net/)

  • L2〜L4(Ethernet / IP / TCP / UDP / SCTP / DCCP)
  • Netfilter(iptables、nftables、conntrack)
  • Netlinkソケット(ユーザ空間↔カーネル通信)
  • XDP(eXpress Data Path)— NICドライバ直下でeBPFを動かし超低遅延
  • io_uringネットワーク操作
  • TLS offload(kTLS)

5. ブロック層 (block/, drivers/md/)

  • I/Oスケジューラ:mq-deadline、kyber、bfq、none
  • マルチキューblock layer(blk-mq)
  • Device Mapper(LVM、dm-crypt、dm-raid)
  • md(ソフトウェアRAID)

6. デバイスドライバ (drivers/)

カーネルソースの過半を占める最大サブシステム。USB、PCI、SCSI、NVMe、ネットワーク、グラフィックス(DRM/KMS)、サウンド(ALSA)、入力(evdev)など。

7. セキュリティ (LSM: Linux Security Module)

フック型のセキュリティ拡張機構。SELinuxAppArmorTOMOYOYamaLandlockSMACK などの「スタック可能な」セキュリティモジュールを挿入できる。

Linuxディストリビューション

Linuxカーネル単体ではOSとして動かない。シェル、ユーティリティ、パッケージマネージャ、デスクトップ環境などを組み合わせた ディストリビューション が「ユーザが使うLinux」である。

【図7】主要Linuxディストリビューション系統図:

graph LR Linux["Linuxカーネル"] Linux --> Debian["Debian系"] Linux --> RH["Red Hat系"] Linux --> Arch["Arch系"] Linux --> SUSE["SUSE系"] Linux --> Others["その他"] Debian --> DebianD["Debian"] Debian --> Ubuntu["Ubuntu"] Ubuntu --> Mint["Linux Mint"] Ubuntu --> Pop["Pop!_OS"] Ubuntu --> Flavors["Kubuntu / Xubuntu / Lubuntu"] Ubuntu --> Ele["elementary OS"] Debian --> Kali["Kali Linux"] RH --> Fedora["Fedora"] RH --> RHEL["RHEL"] RH --> CentOS["CentOS Stream"] RH --> Rocky["Rocky / AlmaLinux"] RH --> AWS["Amazon Linux"] Arch --> ArchL["Arch Linux"] Arch --> Manjaro["Manjaro"] Arch --> Endeavour["EndeavourOS"] SUSE --> openSUSE["openSUSE"] SUSE --> SLES["SLES"] Others --> Gentoo["Gentoo"] Others --> Slack["Slackware"] Others --> Nix["NixOS"] Others --> Alpine["Alpine"] Others --> Android["Android"]

コアコンポーネント

カーネル(Kernel)

OSの中核。ハードウェアに直接触れる最も特権的なソフトウェア。カーネルが提供する主要サービスは以下に集約される。

mindmap root((カーネル)) CPU管理 スケジューリング プロセス生成・終了 コンテキストスイッチ 割り込み処理 メモリ管理 仮想メモリ ページング スワップ メモリ保護 NUMA I/O管理 デバイスドライバ 割り込みハンドラ DMA ブロック層 キャラクタ層 ファイルシステム VFS ext4/xfs/btrfs ジャーナリング ページキャッシュ ネットワーク TCP/IP ソケット Netfilter eBPF/XDP セキュリティ LSM ユーザ/グループ/UID Capabilities 名前空間 cgroups IPC パイプ シグナル 共有メモリ セマフォ メッセージキュー ソケット

シェル(Shell)

シェルはユーザとカーネルの仲介者。コマンド解析、変数展開、ワイルドカード展開(グロブ)、ヒストリ、ジョブ制御、パイプ/リダイレクト、関数定義、スクリプト実行を担う。

シェル 起源 特徴 デフォルト採用例
sh (Bourne Shell) 1977, AT&T POSIX標準 /bin/sh(多くの最小環境)
bash (Bourne Again Shell) 1989, GNU sh拡張、豊富な機能 Linux多数、macOS 〜10.14
csh / tcsh 1978 C風文法 FreeBSDのroot
ksh (Korn Shell) 1983 先進的機能 AIX、Solaris
zsh 1990 補完強化、テーマ(Oh My Zsh) macOS 10.15〜、Kali
fish 2005 初心者向け、設定不要で高機能 ポータブル
PowerShell 2006, Microsoft オブジェクト指向、.NET統合 Windows、クロスプラットフォーム
cmd.exe 1987 Windows伝統 Windows
nushell 2019, Rust製 構造化データ指向 モダン代替

システムライブラリ

glibc(GNU C Library)

Linuxの標準Cライブラリ。POSIX・ISO C・XSI準拠のAPIを提供し、システムコールのラッパ(open, read, fork, pthreadcreatepthread_create など)、文字列操作、数学関数、ロケール、DNSレゾルバ、ダイナミックローダ(ld-linux.so)を含む。

主要な派生/代替:

  • musl libc:軽量・簡潔、Alpine Linuxで採用。
  • uClibc / uClibc-ng:組み込み向け。
  • BionicAndroid用libc(glibcではなく、BSDベース)。
  • Newlib:RTOS向け。
  • ucrt (Universal CRT)Windows 10以降のCRT。

C++ 標準ライブラリ

libstdc++(GNU)、libc++(LLVM)、Microsoft STL。C++20/23の <thread><thread><atomic><atomic><filesystem><filesystem><coroutine><coroutine> などを提供。

その他重要ライブラリ

  • libssl / libcrypto(OpenSSL、LibreSSL、BoringSSL)
  • libcurllibnghttp2
  • zlibliblzmalibzstd(圧縮)
  • libX11libwayland-client(GUI)
  • systemd クライアントライブラリ(libsystemd)

システムユーティリティとデーモン

Linuxの典型的な常駐プロセス

flowchart TB S["systemd (PID 1) initプロセス (カーネルの親)"] S --> J["systemd-journald 構造化ログ"] S --> U["systemd-udevd デバイスホットプラグ"] S --> L["systemd-logind ユーザセッション管理"] S --> N["systemd-networkd ネットワーク設定"] S --> R["systemd-resolved DNS"] S --> T["systemd-timesyncd NTP (簡易)"] S --> NM["NetworkManager ネットワーク管理 (GUI系)"] S --> SSH["sshd SSHサーバ"] S --> C["cron / systemd.timer 定期実行"] S --> RS["rsyslog 伝統的syslog"] S --> CU["cups 印刷"] S --> A["avahi-daemon mDNS (Bonjour)"] S --> B["bluetoothd Bluetooth"] S --> P["pulseaudio / pipewire オーディオ"] S --> X["X11 / Wayland compositor GUI"] S --> PD["polkit / dbus 権限・バス"] S --> CT["containerd / dockerd コンテナ"]

macOSでは launchd(PID 1)がこれらをすべて統合している。Windowsでは services.exe がサービスマネージャを担う。


ブートプロセスと初期化

電源ボタンを押してからログインプロンプトが現れるまで、OSは複雑な一連の初期化を行う。

UEFIブートの流れ(現代的x86-64 PC)

この図では、「ファームウェア → ブートローダ → カーネル → init/systemd」という主な責務の受け渡しを見る。

sequenceDiagram participant PSU as電源 participant CPU as CPU participant UEFI as UEFI Firmware participant ESP as EFI System Partition participant GRUB as GRUB2 bootloader participant Kernel as Linux Kernel participant systemd as systemd PSU->>CPU: 電源ON、リセット解除 CPU->>UEFI: リセットベクタから実行 UEFI->>UEFI: POST(Power-On Self Test) UEFI->>UEFI: ハードウェア初期化(RAM、PCIe) UEFI->>ESP: /EFI/BOOT/BOOTX64.EFI読み込み UEFI->>GRUB: 制御移行 GRUB->>GRUB: メニュー表示、設定読み込み GRUB->>Kernel: vmlinuz、initramfsロード Kernel->>Kernel: アーキ初期化、MMU有効化 Kernel->>Kernel: ドライバ読み込み、ファイルシステムマウント Kernel->>systemd: /sbin/init (=systemd) 実行 systemd->>systemd: unit file読み込み、サービス起動 systemd->>systemd: target達成(multi-user.target, graphical.target)

詳細フェーズ

Phase 1: ファームウェア(UEFI / BIOS)

  • BIOS(Basic Input/Output System、1981〜):16bitリアルモードで起動、512バイトのMBRを読み込む。現代ではレガシー扱い。
  • UEFI(Unified Extensible Firmware Interface、2005〜):モジュラー、GPTパーティション対応、セキュアブートネットワーク起動、GUI提供、Boot Managerを内蔵。ARM、x86-64RISC-Vで標準。
  • Coreboot / LinuxBoot:オープンソースファームウェア。Google Chromebookで採用。

Phase 2: ブートローダ

ブートローダ 対象 特徴
GRUB2 Linux主流 マルチブート、スクリプト
systemd-boot Linuxモダン シンプル、UEFIネイティブ
rEFInd Macマルチブート UEFIグラフィカル
Windows Boot Manager (bootmgr) Windows BCD設定
iBoot iPhone/iPad SecureBoot
bootrom + iBSS + iBEC iOS 多段階チェーン
U-Boot 組み込み ARM, RISC-V定番
SYSLINUX / ISOLINUX / PXELINUX 特殊用途 ライブCD、PXEブート

ここで ESP(EFI System Partition)UEFI用の起動ファイルを置く専用パーティション、initramfs は本番のルートファイルシステムをマウントする前に一時的に使う最小Linux環境である。

Phase 3: カーネルのロードと初期化

  1. 展開vmlinuz は通常gzip/xz/zstd圧縮された bzImage で、先頭のdecompressorが自身を展開する。
  2. アーキテクチャ初期化arch/x86/boot/compressed/head64.Sarch/x86/boot/compressed/head_64.Sstartkernel()start_kernel() へ。
  3. メモリマップ取得:e820テーブル(BIOS)またはEFI memory mapから物理メモリを把握。
  4. ページテーブルセットアップ:Identity mapping → カーネル仮想アドレス空間構築。
  5. startkernel()start_kernel()(init/main.c):各サブシステム初期化 — スケジューラ、割り込み、RCU、タイマ、コンソール、rest_init()、kernel_initスレッド起動。
  6. initramfs:一時ルートファイルシステム。ドライバをロードし、真のルートを見つけてマウント。
  7. init プロセスの起動:PID 1として /sbin/init(systemd、OpenRC、SysV init)をexec

Phase 4: ユーザ空間初期化(systemd)

systemdは依存関係グラフで並列にサービスを起動する。主な単位:

  • .service — サービス(デーモン)
  • .target — グループ化(ランレベル相当:graphical.targetmulti-user.targetrescue.target)
  • .socket — ソケット起動
  • .timer — cron代替
  • .mount / .automount — ファイルシステム
  • .path — パス監視による起動
  • .slice — cgroupツリー

macOSのブート

Power On
  → Boot ROM (UEFI互換、Apple SiliconではiBoot)
  → LLB (Low-Level Bootloader)
  → iBoot
  → Kernel Cache (prelinkedkernel / immutablekernel)
  → XNU (Mach + BSD)
  → launchd (PID 1)
  → System Services (mDNSResponder, WindowServer, loginwindow)
  → ユーザログイン → Finder, Dock, SystemUIServer

Apple Silicon(M1/M2/M3/M4)ではSecure Enclave、Boot Policy、Signed System Volume(SSV)による厳格なセキュアブート。LocalPolicyに署名されない限り実行不可。

Windowsのブート

Power On
  → UEFI firmware
  → Windows Boot Manager (bootmgfw.efi)
  → winload.efi(OS loader)
  → NTOSKRNL.EXE(カーネル)
  → HAL、ドライバ(BOOT_START)
  → Session Manager (smss.exe, PID 4)
  → Local Security Authority (lsass.exe)
  → Win Logon (winlogon.exe)
  → Service Control Manager (services.exe)
  → ログイン → explorer.exe

プロセス管理

ヒント

プロセスは「実行中のプログラム」です。複数のプロセスが同時に動いて見えるのは、OSが高速で切り替えて(コンテキストスイッチ)いるからです。

プロセスとは

プロセス は実行中のプログラムの動的実体であり、以下を保持する:

  • アドレス空間:テキスト(コード)、データ、BSS、ヒープ、スタック、メモリマップ領域
  • 実行コンテキスト:レジスタ(PC、SP、汎用、浮動小数点、SIMD)、モード情報
  • リソース:オープンファイル(ファイルディスクリプタ)、ソケット、シグナルマスク
  • プロパティ:PID、PPID、UID/GID、優先度、CPU時間、作業ディレクトリ、環境変数
  • 状態:実行中、実行可能、ブロック中、停止中、ゾンビ

Linuxのプロセス構造体 taskstructtask_struct

include/linux/sched.h に定義された、Linuxで最大級の構造体(数千行、1万行超のこともある)。主要フィールド:

struct task_struct {
    unsigned int            __state;        // TASK_RUNNING, TASK_INTERRUPTIBLE, ...
    pid_t                   pid, tgid;      // PIDとスレッドグループID
    struct task_struct      *parent;
    struct list_head        children, sibling;
    struct mm_struct        *mm;            // メモリ記述子(ページテーブル等)
    struct fs_struct        *fs;            // ルート/作業ディレクトリ
    struct files_struct     *files;         // ファイルディスクリプタテーブル
    struct signal_struct    *signal;
    struct sighand_struct   *sighand;
    const struct cred       *cred;          // UID/GID/capabilities
    struct sched_entity     se;             // CFS/EEVDF用
    struct sched_rt_entity  rt;             // リアルタイム用
    struct sched_dl_entity  dl;             // DEADLINE用
    int                     prio, static_prio, normal_prio;
    unsigned int            rt_priority;
    unsigned int            policy;         // SCHED_NORMAL, SCHED_FIFO, ...
    cpumask_t               cpus_mask;      // CPUアフィニティ
    u64                     utime, stime;   // ユーザ/システムCPU時間
    struct nsproxy          *nsproxy;       // 名前空間
    struct css_set          *cgroups;       // cgroup所属
    // ... 数百のフィールド
};

プロセス状態遷移

この図では、プロセスが「実行可能」「実行中」「待ち」「停止」「ゾンビ」をどう行き来するかを流れで押さえる。

stateDiagram-v2 [*] --> 新規生成: fork()/clone() 新規生成 --> 実行可能: スケジューラキューに追加 実行可能 --> 実行中: CPUに割り当て 実行中 --> 実行可能: タイムスライス消化、高優先プロセス到着 実行中 --> 割り込み可能待ち: wait()、read() 等 実行中 --> 割り込み不可待ち: ディスクI/O待ち等 実行中 --> 停止: SIGSTOP、デバッガ 割り込み可能待ち --> 実行可能: シグナル、I/O完了 割り込み不可待ち --> 実行可能: I/O完了 停止 --> 実行可能: SIGCONT 実行中 --> ゾンビ: exit() ゾンビ --> [*]: 親がwait() で回収

Linuxの状態コード(ps のSTAT列):

  • R — Running (実行中or実行可能)
  • S — Sleeping (割り込み可能)
  • D — Uninterruptible sleep (通常ディスクI/O、killできない)
  • T — Stopped (SIGSTOP後)
  • t — Tracing stop (デバッガ)
  • ZZombie (終了したが親がwaitしていない)
  • I — Idle kernel thread

プロセス生成:forkとexec

UNIXの美しい設計:

このコードでは、「まず fork() で親子に分かれ、その後に子だけが exec() で別プログラムへ置き換わる」というUNIX流の基本形を見る。

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>

int main(void) {
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        // 子プロセス
        execlp("/bin/ls", "ls", "-l", NULL);
        perror("exec failed");  // execが成功すればここには来ない
        return 1;
    } else {
        // 親プロセス
        int status;
        waitpid(pid, &status, 0);
        printf("child exited with %d\n", WEXITSTATUS(status));
    }
    return 0;
}

fork() は親プロセスのほぼ完全なコピーを作り、exec() は現在のプロセスを別のプログラムで置き換える。この分離により、子プロセスのファイルディスクリプタやシグナルハンドラをexec前に調整する柔軟性が得られる(シェルのリダイレクトはこれを利用)。

Copy-on-Write(COW)

素朴な fork() はアドレス空間全体をコピーするため高コスト。現代OSCopy-on-Write でこれを最適化する:

  1. fork() 時、親子ともにページテーブルは同じ物理ページを指す。
  2. ただしエントリは読み取り専用にマーク。
  3. どちらかが書き込もうとするとページフォルト(#PF, write protect violation)発生。
  4. カーネルが当該ページのコピーを作り、書き込んだプロセスのページテーブルを新ページにリダイレクト。
  5. 読み取りのみのページは永遠に共有(典型的には共有ライブラリやテキスト領域)。

多くの fork() の後にすぐ exec() が呼ばれるケースでは、COWにより実際のコピーはほとんど発生しない。

プロセス階層とinit

Unixでは全プロセスが唯一の祖先PID 1(init/systemd)に辿り着く木構造を成す。親プロセスが子より先に終了した場合、孤児(orphan)プロセスはinitに再親子付けされ、ゾンビ回収はinitの責任となる。

Windowsのプロセスモデル

Windowsプロセスは以下の点でUnixと異なる:

  • fork() がないCreateProcess() は一度に新プログラムを起動する。
  • プロセス作成が高コストスレッド作成の方が推奨される(Windowsでの軽量並行処理の伝統)。
  • Job Object:プロセスグループを包括的に管理。cgroup的役割。
  • プロセスのハンドル:オブジェクトマネージャで管理、参照カウント。

スレッドと並行性

ヒント

スレッドは「プロセスの中で並行に走る軽量な実行単位」です。プロセスより起動が速く、メモリを共有できるため、並列処理や非同期I/Oの基盤になります。

スレッドとは

スレッド は同一プロセスのアドレス空間を共有する実行の流れ。プロセスが「家」なら、スレッドは「その中で同時に活動する人々」。

特性 プロセス スレッド
アドレス空間 独立 共有
ファイルディスクリプタ 独立 共有
スタック 一つ スレッド固有
レジスタ 一つ スレッド固有
シグナルマスク 共有 スレッド固有
生成コスト 高(数ms〜数十ms) 低(数μs〜数百μs)
コンテキストスイッチ 重い(アドレス空間切替あり) 軽い
通信 IPC(パイプ、ソケット、共有メモリ) 直接メモリアクセス
安全性 独立で頑健 共有ゆえ競合リスク

カーネルスレッドvsユーザスレッド

  • カーネルスレッド(1:1モデル)OSが各スレッドをスケジュール。真の並列性を活用可能。Linux pthreadWindows thread、Java (from JVM), .NETはこれ。
  • ユーザスレッド(N:1モデル):ユーザ空間ライブラリがスケジュール。I/Oブロックで全スレッドが停止する欠点。初期のJava green threads、Ruby 1.8。
  • ハイブリッド(M:Nモデル):ユーザスレッドを少数のカーネルスレッドにマップ。SolarisのLWP、Goのgoroutines、Erlangのprocesses、Rustのasyncタスクはこれに近い。
  • 軽量スレッド / ファイバー:協調的スケジューリング、ユーザが yield する。Windows Fiber、Project Loom (Java 21+)、Kotlin Coroutine。

POSIX Threads(pthread)

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void *worker(void *arg) {
    int id = *(int*)arg;
    printf("Thread %d running on TID %ld\n", id, (long)pthread_self());
    sleep(1);
    return NULL;
}

int main(void) {
    pthread_t th[4];
    int ids[4] = {0,1,2,3};
    for (int i = 0; i < 4; i++)
        pthread_create(&th[i], NULL, worker, &ids[i]);
    for (int i = 0; i < 4; i++)
        pthread_join(th[i], NULL);
    return 0;
}

pthread APIは以下を提供:

  • pthreadcreatepthread_create, pthreadjoinpthread_join, pthreaddetachpthread_detach, pthreadexitpthread_exit
  • pthreadmutextpthread_mutex_t, pthreadcondtpthread_cond_t, pthreadrwlocktpthread_rwlock_t, pthreadbarriertpthread_barrier_t, pthreadspinlocktpthread_spinlock_t
  • pthreadkeycreatepthread_key_create(スレッドローカルストレージ)
  • pthreadsetaffinitynppthread_setaffinity_np(CPUアフィニティ)
  • pthreadsetcancelstatepthread_setcancelstate, pthreadsetcanceltypepthread_setcanceltype

Linuxにおけるスレッド実装の歴史

  1. LinuxThreads(1996〜):各スレッドが別PID、シグナル扱いに難あり。
  2. NGPT (Next Generation POSIX Threads):IBMの試み、失敗。
  3. NPTL (Native POSIX Thread Library, 2003〜):1:1モデル、clone() + futex活用。現行標準。

NPTLでは clone(CLONEVMCLONEFSCLONEFILESCLONESIGHANDCLONETHREADCLONESYSVSEMCLONESETTLSCLONEPARENTSETTIDCLONECHILDCLEARTID,...)clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID, ...) で軽量スレッドを生成。

並行性vs並列性

  • 並行性(Concurrency):複数の処理が論理的に同時進行(時分割でも可)。
  • 並列性(Parallelism):複数の処理が物理的に同時実行(マルチコア必須)。

Rob Pikeの箴言:「Concurrency is not parallelism.」Goのgoroutineは「並行」を、複数コアで実行されれば「並列」にもなる。

メモリモデル

マルチコアCPUでは、各コアに別キャッシュがあるため、プログラムの書いた順と、他コアから見える書き込み順が一致しない場合がある。これを定義するのがメモリモデル

  • Sequential Consistency(SC):直感的だが性能ペナルティ大。
  • Total Store Order(TSO)x86-64が採用。store → loadのリオーダリングのみ許す。
  • Release Consistency / Acquire-Release:ARM、RISC-Vが採用。明示的バリア必要。

C11 / C++11memoryorderseqcstmemory_order_seq_cstacquirereleaserelaxedconsume を提供。プログラマが原子操作に明示的にメモリ順序を指定する。

std::atomic<int> flag{0};
std::atomic<int> data{0};

// スレッドA
data.store(42, std::memory_order_relaxed);
flag.store(1, std::memory_order_release);  // release: これ以前の書き込みが見える保証

// スレッドB
while (flag.load(std::memory_order_acquire) == 0);  // acquire: これ以降の読み込みがリリース以前の書き込みを見る保証
assert(data.load(std::memory_order_relaxed) == 42);

Futex — Linuxの同期プリミティブ基盤

Futex (Fast Userspace muTEX)Linux 2.5.7 (2002) で導入。ユーザ空間の整数変数を使い、コンテンションがない場合はカーネル遷移なくmutexを取得できる。コンテンション時のみ futex() syscallでカーネルに待機をキューイング。

glibcpthreadmutextpthread_mutex_t、Rustの std::sync::Mutex、Goのチャネル、Javaの LockSupport.park/unpark は内部でfutexを使う。


CPUスケジューリング詳細

CPUスケジューラは「次にどのプロセス/スレッドを実行するか」を決める。現代OSには、通常プロセス用、リアルタイム用、アイドル用など複数のスケジューリングクラスが共存する。

スケジューリング目標とトレードオフ

目標 意味 対立する目標
公平性(Fairness) すべてのプロセスに妥当なCPUを配分 スループット
スループット(Throughput) 単位時間あたり完了タスク数 応答性
応答性(Responsiveness) ユーザ入力への低遅延 スループット
ターンアラウンド時間 ジョブ投入〜完了までの時間 優先度
待ち時間(Wait time) 実行可能キューでの待機時間
CPU利用率 CPUがbusyな割合 省電力
省電力 モバイル/IoTでは最優先 性能
予測可能性 RTOSでは決定性 平均性能

古典的アルゴリズム

1. FCFS(First Come First Served)

到着順に実行、ノンプリエンプティブ。実装簡単だがconvoy効果(大きなジョブが小さなジョブをブロック)で平均待ち時間悪化。

2. SJF / SRTF(Shortest Job First / Shortest Remaining Time First)

最短の次CPUバーストを持つプロセスを選ぶ。平均待ち時間最小(証明可)だが、実際のCPUバースト長は事前に分からず推定が必要。指数移動平均で過去バーストから予測する:

τn+1=αtn+(1α)τn\tau_{n+1} = \alpha t_n + (1-\alpha) \tau_n

ここで tnt_n は直近バースト実測、τn\tau_n は推定値、α[0,1]\alpha \in [0,1]

3. ラウンドロビン(RR)

プロセスに固定タイムクォンタム q を与え、使い切ったらキュー末尾に戻す。q が小さすぎると切替オーバーヘッド、大きすぎると応答性悪化。典型的 q=10q = 10 ms〜 100 ms。

4. 優先度ベース

プロセスに優先度を付与、高優先を選択。starvation(飢餓) 防止のため aging で待機中の優先度を徐々に上げる。

5. 多段フィードバックキュー(MLFQ)

複数のキューを優先度別に並べ、タイムクォンタムを使い切ったら一段下のキューへ。I/Oバウンドは高優先、CPUバウンドは低優先に自然に分化する。Solarisと古いWindows、Mac OS Xの原型。

Linuxの現代的スケジューラ

CFS(Completely Fair Scheduler, 2007〜2023)

Ingo Molnárによる設計。赤黒木(rbtreerb_tree)で vruntime(virtual runtime)をキーに実行可能タスクを順序付ける。vruntime は「優先度差を補正した仮想的な実行時間」で、最小vruntimeのタスクを次に実行する。

理想:n プロセスが完全公平にCPUを共有するとき、各プロセスの実行時間は T/n になる。CFSはこれを近似する。

重み(weight)はnice値から決まる:nice=0 → 1024、nice=-20 → 88761、nice=19 → 15。vruntimeは実行時間を重みで補正した値:

\text{vruntime} += \text{delta\_exec} \times \frac{\text{NICE\_0\_LOAD}}{\text{weight}}

EEVDF(Earliest Eligible Virtual Deadline First, Linux 6.6〜)

Peter Zijlstraらによる後継。各リクエスト(=タイムスライス)に仮想デッドラインを割り当て、eligible なタスクの中でデッドラインが最も早いものを選ぶ。ここで eligible は「今この時点で実行候補にしてよい」という意味で、レイテンシ要求(schedsetattrsched_setattrschedruntimesched_runtime 指定)を尊重しやすい。

リアルタイムクラス

  • SCHEDFIFOSCHED_FIFO:優先度内FIFO、自発的yieldまで実行。リアルタイム。
  • SCHEDRRSCHED_RR:FIFOにタイムスライス追加。
  • SCHEDDEADLINESCHED_DEADLINE:EDF + CBS(Constant Bandwidth Server)で (runtime, deadline, period) を指定。Hard RTタスクに適する。
  • SCHEDOTHERSCHED_OTHER (=SCHED_NORMAL):CFS/EEVDFで管理。
  • SCHEDBATCHSCHED_BATCH:CPUバウンドでレイテンシ不要。
  • SCHEDIDLESCHED_IDLE:最低優先度、他が何もないとき。

マルチコア・スケーラビリティ

現代のLinuxはコアごとに per-CPUランキュー を持ち、互いに独立にスケジュールする。ランキュー は「そのCPUで実行待ちしているタスクの待ち行列」のことで、負荷分散(load balancing) はペリオディックに動き、アンバランスを検知したら タスクマイグレーション で再配置する。

関連概念:

  • CPU affinity(schedsetaffinitysched_setaffinity, taskset)
  • isolcpus カーネルパラメータ(特定コアをスケジューラから除外)
  • cgroup cpuset(cgroupでCPU集合を制限)
  • NUMA awareness(同一ノード内のコア優先選択、remote memoryアクセスを避ける)

macOSのスケジューラ

Machベースの優先度スケジューラ。Grand Central Dispatch(GCD)のQoSクラス(user-interactive, user-initiated, utility, background)がシステム全体の優先度に反映される。M1以降は E-cores(efficiency)P-cores(performance) のヘテロジニアス設計でスケジューラが電力最適化を行う。

Windowsのスケジューラ

32段階の優先度(0〜31)。0〜15が通常クラス、16〜31がリアルタイムクラスpriority boost によりI/O完了直後やフォアグラウンドウィンドウのスレッドに一時的に優先度を上げる。


同期機構とプロセス間通信

マルチプロセス・マルチスレッド環境では、共有資源への同時アクセスを調整する仕組みが不可欠。

基本同期プリミティブ

1. ロック(Mutex: Mutual Exclusion)

最も基本的。クリティカルセクションに一度に一つのスレッドしか入れない。

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
// クリティカルセクション
pthread_mutex_unlock(&lock);

実装はfutex + atomic CASベース。競合がなければカーネル遷移なし。

2. スピンロック

ロック取得までビジーループ(CPUを回して待つ)。カーネル内の短時間クリティカルセクションで使う。ユーザ空間では通常推奨されない(CPU無駄、電力浪費)。

void spin_lock(atomic_int *lock) {
    while (atomic_exchange(lock, 1) == 1) {
        // pause命令で電力削減
        __builtin_ia32_pause();
    }
}

3. リーダライタロック(rwlock)

複数リーダ同時可、ライタは排他。読み多数、書き少数のケースで有効。

4. セマフォ

Dijkstraが1965年に提案。P() (wait) で減算、V() (signal) で加算。0以上の整数でリソース数を管理。

  • バイナリセマフォ:mutex相当
  • カウンティングセマフォ:リソースプール管理

POSIX: seminitsem_init, semwaitsem_wait, sempostsem_post。SystemV: semget, semop

5. 条件変数(Condition Variable)

「ある条件が真になるまで待つ」。必ずmutexと組み合わせて使う。

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  c = PTHREAD_COND_INITIALIZER;
int ready = 0;

// 待機側
pthread_mutex_lock(&m);
while (!ready) pthread_cond_wait(&c, &m);  // mutexを解放してwait
// ここではmutex再取得済み、readyが真
pthread_mutex_unlock(&m);

// 通知側
pthread_mutex_lock(&m);
ready = 1;
pthread_cond_signal(&c);  // またはpthread_cond_broadcast
pthread_mutex_unlock(&m);

while (!ready)spurious wakeup 対策で必須。

6. バリア

Nスレッドが揃うまで全員待機。並列計算のフェーズ同期に使う。

7. モニタ

高水準同期抽象。Javaの synchronized、C# の lock、Pythonの threading.Condition が該当。

8. RCU(Read-Copy-Update)

Linuxカーネル内で広く使われる。読み手はロックなし、書き手は新しいコピーを作って公開後、古いコピーをgrace period後に削除。読み支配的なワークロードで極めて高速。

プロセス間通信(IPC)

プロセス間はアドレス空間が独立しているため、専用の通信機構が必要。

1. パイプ(Pipe)

ls -l | grep "^d" | wc -l

UNIXの美しい発明。無名パイプ pipe(2)pipe(2) と名前付きパイプ mkfifo(3)mkfifo(3)。単方向、バッファリング、EOF伝達。

2. シグナル

非同期イベント通知。SIGTERM(終了要求)、SIGKILL(強制終了、ハンドル不可)、SIGSEGV(メモリ違反)、SIGINT(Ctrl-C)、SIGCHLD(子プロセス状態変化)、SIGUSR1/2(ユーザ定義)など。

#include <signal.h>
void handler(int sig) { /* ... */ }
signal(SIGINT, handler);  // 古いAPI
// モダンにはsigaction() を使う

シグナルハンドラ内で使える関数は async-signal-safe に限られる(printf は不可、write は可)。

3. 共有メモリ

複数プロセスが同一物理ページを自アドレス空間にマップ。最速のIPCだが同期は別途必要。

  • POSIX共有メモリshmopenshm_open + mmap
  • SystemV共有メモリshmget + shmat(レガシー)
  • memfd_create / memfd_secret(Linux)
  • ハイブリッドアプローチ:io_uringのSQE/CQEリングバッファも共有メモリ

4. メッセージキュー

  • POSIX mqueuemqopenmq_open, mqsendmq_send, mqreceivemq_receive
  • SystemV msgmsgget, msgsnd, msgrcv

5. ソケット

6. D-Bus

Linuxデスクトップ(GNOME/KDE)およびsystemdで使われる高水準IPC。オブジェクト、メソッド、シグナル、プロパティの概念を提供。gdbusbusctldbus-send

7. Mach Messages(macOS/iOS)

XNUのマイクロカーネル的基盤。ポートとメッセージで通信。XPC、NSXPCConnectionの基盤。

8. Windows IPC

  • 名前付きパイプ(\\.\pipe\name)
  • Mailslot
  • 共有メモリ(File Mapping)
  • COM / DCOM
  • RPC
  • WM_COPYDATA(GUIウィンドウメッセージ)
  • Windows Sockets (Winsock)

デッドロック・飢餓・レースコンディション

デッドロック(Deadlock)

二つ以上のプロセスが互いに相手の保有リソースを待ち、全員が進まなくなる状態。

【図8】デッドロックの循環待ち:

graph LR A["Process A / 保有: Lock1 / 待機: Lock2"] B["Process B / 保有: Lock2 / 待機: Lock1"] L1["Lock1"] L2["Lock2"] A -->|保有| L1 B -->|保有| L2 A -.待機.-> L2 B -.待機.-> L1

Coffman条件

デッドロックが起こるには次の4つが同時成立する必要がある:

  1. Mutual Exclusion(相互排除):リソースは一度に一つのプロセスしか保有できない。
  2. Hold and Wait(保有と待機):既にリソースを保有しつつ、別のリソースを待つ。
  3. No Preemption(非奪取):リソースを強制的に取り上げることはできない。
  4. Circular Wait(循環待ち)プロセス間で循環的な待ち関係がある。

デッドロック対策

予防(Prevention):4条件のいずれかを崩す

  • 相互排除を崩す:リソースを共有可能にする(常に可能とは限らない)
  • 保有と待機を崩す:全リソースを最初に一括取得(lockallthenproceed()lock_all_then_proceed())
  • 非奪取を崩す:待機時に保有リソースを解放、再取得時にやり直し
  • 循環待ちを崩す:リソースに全順序を定義し、番号の昇順でしか取得しない → Linuxカーネルlockdep が自動検証

回避(Avoidance):実行時チェック

  • Banker’s Algorithm(Dijkstra, 1965):リソース要求時、安全状態が保てるかシミュレート。安全状態 = 全プロセスが満足する実行順序が存在する状態。要求プロセス数・リソース種類・数すべて事前判明が前提で、汎用OSでは使いにくい。

検出と回復(Detection & Recovery):定期的にリソース要求グラフを走査し、サイクルを検出したら回復措置

  • プロセスの強制終了
  • ロールバック(DBは普遍的にこれを行う)
  • 資源の強制解放

無視(Ostrich Algorithm):多くの汎用OS(Linux, Windows)は「起きたら困るけど滅多にないから対処しない」方針。Tanenbaumはこれを「ダチョウ法」と命名。

Linuxのlockdep

LinuxカーネルCONFIGLOCKDEPCONFIG_LOCKDEP でコンパイルすると、実行時にすべてのロック取得順序を記録し、潜在的デッドロックパターン(循環)を検出して警告する。これにより広範なカーネルロックのバグが発見された。

飢餓(Starvation)

優先度の低いタスクが、高優先タスクに常に追い抜かれて永遠に実行されない状態。エイジング(aging) = 待機時間に応じて優先度を動的に上げる、で緩和。

優先度逆転(Priority Inversion)

低優先プロセスが持つロックを高優先プロセスが待つ間、中優先プロセスが割り込んでCPUを奪う現象。

歴史的事件:火星探査機Mars Pathfinder(1997) でこれが発生し、タイムアウトによるシステムリセットが多発した。VxWorksの priority inheritance protocol を有効にして解決。

対策:

  • Priority Inheritance:ロック保有者を一時的に最高待機者の優先度まで引き上げ。
  • Priority Ceiling:各ロックに最高優先度を割り当て、取得者はそれに昇格。

POSIXでは pthreadmutexattrsetprotocol(PTHREADPRIOINHERIT)pthread_mutexattr_setprotocol(PTHREAD_PRIO_INHERIT) で指定可能。

レースコンディション(Race Condition)

複数スレッドの実行順序によって結果が変わる、バグの温床。

int counter = 0;
// 10スレッドが各100000回counter++ したら1,000,000になるはず?
// → ならない。counter++ はload, add, storeの3命令で、
//    スレッド間で織り交ざると失われる更新が発生

対策:

  • アトミック操作(__atomic_add_fetch, std::atomic)
  • ミューテックス
  • ロックフリー構造(CASベース)
  • ミュータブルな共有状態を避ける(関数型、Rust所有権)

TOCTOU(Time-of-check to time-of-use)

「チェックした時と使う時の間で状態が変わる」タイプの脆弱性。

if (access(file, W_OK) == 0) {  // チェック時はOK
    fd = open(file, O_WRONLY);  // 攻撃者がsymlinkに差し替えたら?
    write(fd, data, n);
}

対策:openat(ONOFOLLOW)openat(O_NOFOLLOW)、ハンドルベースAPI、capabilities。


メモリ管理

ヒント

プロセスが触れる「アドレス」は本当のメモリ位置ではなく「仮想アドレス」です。OSとMMU(メモリ管理ユニット)が協力して、仮想→物理への変換、分離、保護、拡張(スワップ)を実現しています。

現代OSのメモリ管理は、ハードウェア(MMU, TLB, cache)との連携で成立する巨大なサブシステムです。

メモリ階層

レジスタ          < 1 ns   B単位      各コア内
L1キャッシュ       ~1 ns   32 KB各コア内
L2キャッシュ       ~4 ns   256 KB〜1 MB各コア内
L3キャッシュ      ~10 ns数MB〜数十MB  CPUソケット内共有
DRAM             ~80 ns   GB〜TBソケット越しアクセスは遅い (NUMA)
NVDIMM/Optane   ~300 ns   TB永続、廃番
SSD (NVMe)      ~10 μs   TBブロックデバイス
SSD (SATA)      ~100 μs  TB
HDD             ~10 ms   TBシーク遅延大
Tape / クラウド   ~秒〜分PB

この階層は locality of reference の原理に基づく:

  • 時間局所性:最近使ったデータは近く使われる
  • 空間局所性:あるアドレスを使ったら周辺も使う

キャッシュと仮想メモリシステム(ページキャッシュ、スワップ)はこの仮定で設計されている。

仮想メモリ

プロセスに、物理メモリとは独立した仮想アドレス空間(x86-6448bit = 256TB、最新LA57で57bit = 128PB)を提供。MMUが仮想→物理変換を行う。

利点

ページング

仮想アドレス空間を固定サイズ(典型的に4KB)のページに、物理メモリを同サイズのフレームに分割。ページテーブルで対応関係を保持。

4段ページテーブル(x86-64, 48bit)

 48bit仮想アドレス = | 9 | 9 | 9 | 9 | 12 |
                      PML4 PDPT PD  PTオフセット

 CR3 → PML4 → PDPT → PD → PT → 物理ページフレーム番号

各レベルは512エントリ(9bit)、各エントリは8バイト(64bit)。5段(LA57) はIce Lake以降で利用可、128PBまで対応。

TLB(Translation Lookaside Buffer)

MMUに内蔵された「最近の翻訳結果キャッシュ」。TLBミスすると4回(もしくは5回)のメモリアクセスでページテーブルをウォーク(遅い)。Intel x86-64TLBは典型的にL1 dTLBが64エントリ、L2 STLBが1024〜2048エントリ。

TLBシュートダウン:あるコアがページテーブルを更新したとき、他コアのTLBも無効化するIPI(Inter-Processor Interrupt)が必要。マルチコアでは意外に高コスト。

Huge Pages(大ページ)

通常4KBの代わりに2MBや1GBのページを使うと、TLBエントリで大きな領域をカバーでき、ミスが減る。

  • LinuxTHP(Transparent Huge Pages):自動で昇格
  • 明示的hugetlbfs/proc/sys/vm/nrhugepages/proc/sys/vm/nr_hugepages で予約
  • Windows Large PagesVirtualAlloc(MEMLARGEPAGES)VirtualAlloc(MEM_LARGE_PAGES)

データベース(PostgreSQLの hugepages=onhuge_pages = on、MySQL)やJVM(-XX:+UseLargePages)で有効化するとパフォーマンス改善が見られる。

デマンドページング

プロセス起動時に全ページを物理メモリにロードせず、アクセスされた時にはじめてフォルト経由でロード。未使用コードや初期化データは永遠にロードされない可能性があり、メモリ効率的。

ページ置換アルゴリズム

物理メモリが逼迫したとき、どのページをディスクに追い出すか?

アルゴリズム 概要 評価
FIFO キュー順、古い方から 単純、Belady’s anomalyあり
OPT(最適) 最も遠い将来に使うページ 理論上最適、実装不可
LRU(最近最少使用) 最も古くアクセスされたページ 近似最適、コスト高
Clock / Second-chance 参照ビットで近似LRU 実装簡単、Linuxの基礎
LFU(最少頻度使用) アクセス回数最少 古いけど重要なページが追い出される
ARC(Adaptive Replacement Cache) IBM特許、LRU + LFUハイブリッド ZFSで使用
2Q, CAR, LIRS 近似ARC 各種DBエンジン

Linux2 Q (active/inactive list) + WorkingSet refault + reclaim で実装。

Working Setと スラッシング

Working Set:時刻 t から過去 Δ\Delta 時間にアクセスされたページ集合 W(t,Δ)W(t, \Delta)

スラッシング:物理メモリが全プロセスのworking set総和より小さく、ページフォルトとディスクI/Oが頻発してCPUがほぼidleになる状態。

対策:

  • メモリ追加
  • プロセスをスワップアウト(サスペンド)
  • swappiness パラメータ調整
  • OOM killer(Linuxの最後の手段)

OOM Killerとメモリプレッシャー

Linuxでは、メモリ不足が進みreclaimだけでは回復できなくなると、最終手段として OOM Killer(Out Of Memory Killer) が動く。これは「メモリを多く消費していて、止めたときの回復効果が大きいプロセス」を選んで強制終了し、システム全体の停止を避ける仕組みである。

ここで大事なのは、OOMは「突然プロセスが死んだ不可解な事故」ではなく、メモリプレッシャーが限界を超えた結果 として起きることが多い、という見方である。Linuxでは次のような情報を手がかりにすると流れを追いやすい。

dmesg | tail -50
journalctl -k -n 50
cat /proc/meminfo
cat /proc/pressure/memory
cat /proc/<pid>/oom_score
cat /proc/<pid>/oom_score_adj
  • oom_score は、そのプロセスがOOMの候補になりやすい度合い
  • oom_score_adj は、その候補度合いを人為的に上下させる調整値
  • /proc/pressure/memory は、CPUが「仕事をしたいのにメモリ待ちで進めない」時間を示す

実務では、OOMが起きたら単に「メモリを増やす」だけでなく、

  • どのワークロードがRSSを押し上げたか
  • ページキャッシュと匿名メモリのどちらが膨らんでいたか
  • swappiness やcgroupの制限が適切だったか
  • そもそもメモリリークや過大な同時実行がなかったか

を分けて見る必要がある。コンテナ環境ではcgroup制限に先に当たることも多く、ホスト全体のRAMに余裕があってもコンテナ内のプロセスだけがOOMで落ちることがある。

メモリアロケータ

物理メモリ層:バディアロケータ

ページを 2^n ページの塊(order-n block)で管理。要求時は最小の十分な塊を取り、必要なら分割。解放時はbuddy(兄弟)がfreeなら統合。

  • 外部断片化を大幅に削減
  • 最大orderはCONFIG_FORCE_MAX_ZONEORDER(通常10、4MB塊まで)
  • cat /proc/buddyinfo で確認可能

スラブアロケータ(SLAB / SLUB / SLOB)

同サイズのオブジェクト(taskstructtask_struct, inode, dentry, skbuffsk_buff 等)を効率管理。kmalloc / kmemcacheallockmem_cache_alloc の基盤。

  • SLAB:Jeff Bonwick @ Sunの原型。キャッシュフレンドリだが複雑・メタデータ大
  • SLUB(現Linux標準, 2008〜):Christoph Lameter作、シンプル・高速
  • SLOB:メモリ制約組み込み向け、極小

ユーザ空間のmalloc実装

実装 特徴 採用
ptmalloc2 glibc標準、ロック競合あり Linuxデフォルト
tcmalloc Google、Thread-Caching Chromium、多くのGoogle系
jemalloc Facebook、フラグメンテーション低 FreeBSD、Firefox、Rust旧版
mimalloc Microsoft、Research Microsoft系、一部性能クリティカル
rpmalloc Rampant Pixel、ロックレス ゲームエンジン
snmalloc Microsoft Research、モダン 研究

NUMA(Non-Uniform Memory Access)

マルチソケットサーバでは、各ソケットにローカルRAMがあり、リモートソケットのRAMへのアクセスは数倍遅い。

Socket 0                     Socket 1
  CPU 0,1,2,3,...              CPU 8,9,10,11,...
   ↕ local memory (速)          ↕ local memory (速)
   Node 0 RAM                   Node 1 RAM
         ↕ UPI/Infinity Fabric (遅)

LinuxNUMA対応:

  • numactl コマンド、libnuma
  • カーネルパラメータnuma=offnuma=off
  • mempolicy:MPOLBINDMPOL_BIND, MPOLPREFERREDMPOL_PREFERRED, MPOLINTERLEAVEMPOL_INTERLEAVE
  • numastatnumactl --hardware
  • Transparent NUMA balancing (auto-migrate pages)

Copy-on-Write、Zero-Fill、Demand-Zero

  • Zero-fill on demandmmap(MAPANONYMOUS)mmap(MAP_ANONYMOUS) した領域は全て zeropagezero_page を指す。書き込み時に初めて実メモリ割り当て。
  • COWfork 後の書き込みで初めてコピー。
  • Deduplication (KSM - Kernel Samepage Merging)仮想化ホスト等で同一内容のページを自動統合。

メモリ統計観察

free -h                    # 全体
cat /proc/meminfo          # 詳細
vmstat 1                   # 時系列
ps -o pid,rss,vsz,cmd      # プロセス別
pmap -x <pid>              # プロセス詳細マップ
smem -rs rss               # swap含む
slabtop                    # スラブキャッシュ
cat /proc/buddyinfo        # バディ状態
cat /proc/zoneinfo         # ゾーン別
cat /proc/pagetypeinfo     # 断片化
perf mem record            # メモリアクセスプロファイル

ファイルシステムとI/O

ヒント

Unix系OSでは「すべてはファイル」という哲学が貫かれており、通常のファイルもデバイスも、ソケットも、パイプも同じAPI(open/read/write/close)で扱えます。

ファイルとディレクトリ

ファイル:名前のついたバイトシーケンスに属性(所有者、権限、タイムスタンプ)を付けたもの。

ディレクトリ:ファイル名→inodeの対応表。ディレクトリ自体もファイルの一種(type=directory)。

Unixのファイル階層(FHS)

FHS(Filesystem Hierarchy Standard) は、Unix/Linux系で「どの種類のファイルをどこに置くか」をそろえるための慣習・標準である。

flowchart TB R["/ ルート"] R --> BIN["bin/"] R --> BOOT["boot/"] R --> DEV["dev/"] R --> ETC["etc/"] R --> HOME["home/"] R --> LIB["lib/"] R --> LIB64["lib64/"] R --> MEDIA["media/"] R --> MNT["mnt/"] R --> OPT["opt/"] R --> PROC["proc/"] R --> ROOTD["root/"] R --> RUN["run/"] R --> SBIN["sbin/"] R --> SRV["srv/"] R --> SYS["sys/"] R --> TMP["tmp/"] R --> USR["usr/"] R --> VAR["var/"] USR --> UB["bin/"] USR --> UL["lib/"] USR --> ULO["local/"] USR --> US["share/"] USR --> USC["src/"] VAR --> VLOG["log/"] VAR --> VC["cache/"] VAR --> VLIB["lib/"] VAR --> VS["spool/"]

inode

Unixファイルシステムの中核データ構造。各ファイルに一意のinode番号があり、メタデータとデータブロック位置を保持する。名前そのものはディレクトリ側にあり、inodeは「その実体情報」を持つ。

【図20】inodeの構造:

この図では、ファイル名そのものはinodeに入らず、inode側には属性とデータ位置が入る、という役割分担を見る。

graph LR Inode["inode #54321"] Inode --> T["ファイルタイプ / regular, directory, symlink / char dev, block dev, socket, fifo"] Inode --> M["モード / rwxr-xr-x = 0755"] Inode --> O["所有者UID / GID"] Inode --> L["ハードリンク数"] Inode --> S["サイズ(バイト)"] Inode --> TS["タイムスタンプ / atime, mtime, ctime, btime"] Inode --> BP["ブロックポインタ"] BP --> D["直接ポインタ × 12 / ext4: 先頭48KB"] BP --> I1["単間接ポインタ"] BP --> I2["二重間接ポインタ"] BP --> I3["三重間接ポインタ"] Inode --> X["拡張属性 (xattr)"]

ハードリンク:複数のディレクトリエントリが同じinodeを指す(ln src dst)。 シンボリックリンク:パス名を格納した特殊ファイル(ln -s src dst)。

stat コマンドで詳細確認、ls -i でinode番号表示。

ext4 / XFS / Btrfs / ZFS / APFS / NTFSの比較

ここで ジャーナリング は「更新前後の記録を先に残して、障害時に整合性を戻しやすくする仕組み」、CoW(Copy-on-Write) は「上書きせず新しい場所へ書いてから差し替える方式」、VSSWindowsのVolume Shadow Copy Serviceでスナップショット機能を指す。

特徴 ext4 XFS Btrfs ZFS APFS NTFS
開発元 Linuxコミュニティ SGI→Linux Oracle→Linux Sun→OpenZFS Apple Microsoft
ジャーナリング CoW CoW CoW
最大ファイル 16 TiB 8 EiB 16 EiB 16 EiB 8 EiB 16 TB
最大FS 1 EiB 8 EiB 16 EiB 256 ZiB 8 EiB 256 TB
スナップショット VSS
RAID内蔵
圧縮 lz4, zlib
重複排除
暗号化 fscrypt 実験 EFS
チェックサム メタデータ メタデータ メタデータ
検証 fsck.ext4 xfs_repair btrfs check zpool scrub fsck_apfs chkdsk
主な用途 汎用Linux 大容量・並列 モダンLinux エンタープライズ macOS/iOS Windows

ジャーナリングファイルシステム

クラッシュ時のメタデータ不整合を防ぐ。書き込みをジャーナル(ログ)に記録してからコミット。クラッシュ後はジャーナルを再生して整合性回復。

ext4のモード:

  • journal:データもメタデータもジャーナル(安全、遅い)
  • ordered(デフォルト):メタデータのみジャーナル、ただしデータを先にディスクに書く
  • writeback:メタデータのみ、データ順序保証なし(最速、データ不整合リスク)

Copy-on-Writeファイルシステム

Btrfs、ZFS、APFSが採用。書き込みは既存ブロックを上書きせず、新ブロックに書き、メタデータを原子的に更新。

利点

  • クラッシュ耐性(常に古いバージョンがディスクにある)
  • スナップショットがO(1)
  • 圧縮・暗号化・チェックサム・重複排除と相性が良い

欠点

  • 断片化しやすい(特にランダム更新)
  • メタデータオーバーヘッド

ページキャッシュとバッファキャッシュ

LinuxはディスクI/Oをページキャッシュで透過的にキャッシュする。read() した内容はRAMに保持され、同じ領域の次の read() はRAMから返す。free -hbuff/cache 列がこれ。

Write-back cachewrite() でRAMに書き、後でflushd/pdflush/bdi-flushがディスクに書く。sync/fsync/fdatasync/msync で強制フラッシュ。

Direct I/O(ODIRECTO_DIRECT):ページキャッシュを迂回してディスクに直接I/O。DBMSなど自前キャッシュを持つアプリケーションで使う。

I/Oモデル

1. 同期ブロッキングI/O

ssize_t n = read(fd, buf, count);  // データ来るまでブロック

シンプルだが、並行接続数だけスレッドが必要(C10K問題)。

2. 同期ノンブロッキングI/O

fcntl(fd, F_SETFL, O_NONBLOCK);
while (read(fd, buf, count) < 0 && errno == EAGAIN) {
    // ビジーループ(非効率)
}

3. I/O多重化(Multiplexing)

一つのスレッドで複数fdを監視:

  • select:古い、fd数に上限(FD_SETSIZE=1024)
  • poll:上限なし、fd毎にコピー発生
  • epoll(Linux):O(1)、level/edge triggered、カーネルで状態保持
  • kqueue(BSD/macOS):汎用イベント通知(fd、ファイル変更、シグナル、タイマ)
  • IOCP(Windows):Completion Port、非同期完了通知

4. シグナル駆動I/O

SIGIO で通知(あまり使われない)。

5. 非同期I/O(AIO)

  • POSIX AIOLinux実装は貧弱でほとんど使われない
  • Linux native AIO (libaio):O_DIRECT専用、制限多
  • io_uring(2019〜):SQE/CQE共有リングバッファ、バッチ化、zero-copy、現代的
  • IOCP(Windows):成熟した非同期モデル

io_uringの設計

Jens AxboeによるLinuxの革新的非同期I/O API。

struct io_uring ring;
io_uring_queue_init(32, &ring, 0);

// 提出
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buf, 4096, offset);
io_uring_submit(&ring);

// 完了待ち
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
// cqe->resが結果
io_uring_cqe_seen(&ring, cqe);

特徴:

  • システムコール回数が激減(バッチ提出、バッチ取得)
  • SQ_POLLでカーネルスレッドがbusy pollし、ユーザはsyscallなしでI/O発行可
  • ファイル、ソケット、タイマ、fsyncacceptsend/recv など幅広くサポート
  • IOSQEIOLINKIOSQE_IO_LINK で依存チェーンを形成

メモリマップトファイル(mmap)

ファイルをプロセスのアドレス空間にマップし、ポインタアクセスで読み書き。

int fd = open("data.bin", O_RDWR);
void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
// addrを通して直接操作
*(int*)addr = 42;
msync(addr, size, MS_SYNC);  // ディスクに同期
munmap(addr, size);

メリット:ページキャッシュをそのまま利用、大きなファイルも効率的、複数プロセス共有可。 デメリット:予期せぬページフォルト、SIGBUS(ファイル縮小時)、エラーハンドリングが面倒。

pseudo filesystem(疑似FS)

物理ストレージなしに情報を提供:

  • procfs(/proc)プロセスごとの情報(/proc/<pid>/status/proc/<pid>/status)、カーネル情報
  • sysfs(/sys):デバイスツリー、カーネルパラメータ
  • tmpfs(/tmp, /run, /dev/shm):RAMベースのファイルシステム
  • devtmpfs, devfs:デバイスノード
  • cgroup2fs(/sys/fs/cgroup):cgroup階層
  • debugfs(/sys/kernel/debug):デバッグ用
  • configfs、securityfs、pstore、bpf、tracefs

FUSE(Filesystem in Userspace)

ユーザ空間でファイルシステムを実装できるフレームワーク。SSHFS、NTFS-3G、S3FS、rclone、Google Drive FS等で使われる。


ストレージ管理とRAID

ディスクの物理構造

HDD(Hard Disk Drive)

回転する磁気ディスク、機械式ヘッド。

  • シーク時間(ヘッド移動):5〜15 ms
  • 回転遅延(セクタが下に来る):3〜6 ms(7200rpmで平均4.2ms)
  • 転送時間:データをヘッドが読む
  • IOPS:100〜200程度

最適化:エレベータスケジューラ(C-SCAN)、ディスクキャッシュ、書き込み結合。

SSD(Solid State Drive)

NANDフラッシュメモリ、機械部品なし。

  • 読み込み:25〜100 μs
  • 書き込み:200〜500 μs(消去はms単位)
  • IOPS:数万〜100万(NVMe)
  • 問題:書き換え回数制限(TLC数千回、QLC数百回)、書き込み増幅、GC

対策:TRIM(解放済みブロック通知)、ウェアレベリング(均等消耗)、over-provisioningSLC cache

I/Oスケジューラ(Linux)

ディスクからのI/O要求を並べ替え、マージする。

  • noop / none:並べ替えなし。SSD向き。
  • mq-deadline:期限ベース。汎用、デフォルト。
  • kyber:低遅延向け、マルチキュー。
  • bfq (Budget Fair Queueing)プロセス公平性、デスクトップ向き。

/sys/block/sda/queue/scheduler で確認・変更。

RAID(Redundant Array of Independent Disks)

複数ディスクを組み合わせて、性能や冗長性を向上。

RAID Level 方式 最小枚数 容量 性能 冗長性
RAID 0 ストライピング 2 100% 読書両倍 なし
RAID 1 ミラーリング 2 50% 読倍、書同等 1台障害OK
RAID 5 パリティ分散 3 (N-1)/N 読高、書中 1台障害OK
RAID 6 二重パリティ 4 (N-2)/N 読高、書低 2台障害OK
RAID 10 1+0 4 50% 両高 各ミラーで1台
RAID Z1/Z2/Z3 ZFS 3/4/5 類似5/6 両中 1/2/3台

ハードウェアRAID vsソフトウェアRAID

  • ハードウェアRAID:専用コントローラカード、BBU(Battery Backup Unit)でキャッシュ保護、OSから見えない
  • ソフトウェアRAIDLinuxmd、FreeBSDの geom、SolarisのZFS / Vinum

LVM(Logical Volume Manager)

物理ボリューム(PV)→ ボリュームグループ(VG)→ 論理ボリューム(LV)の階層で柔軟な管理。

物理ディスク (sda)   (sdb)
     ↓               ↓
Physical Volume  Physical Volume
     \           /
    Volume Group "vg_data"
     /           \
Logical Volume   Logical Volume
   "lv_root"      "lv_home"
     ↓               ↓
Filesystem        Filesystem
(ext4)            (xfs)

スナップショット、リサイズ、シンプロビジョニング(lvcreate --thin)、RAIDもサポート。

分散ファイルシステム・オブジェクトストレージ

  • NFS(Network File System, Sun 1984):標準、古典的
  • SMB/CIFS(Samba):Windows相互運用
  • LustreHPC、数千ノード
  • GlusterFS:オブジェクト、スケール
  • Ceph:分散オブジェクト、ブロック、ファイル
  • HDFS(Hadoop):ビッグデータ、大ブロック
  • S3:Amazon、事実上の標準オブジェクトAPI
  • MinIO、GCS、Azure Blob

デバイス管理とドライバ

デバイスの分類

Linuxカーネルはデバイスを以下のクラスに分ける:

  • キャラクタデバイス(char device):バイト単位、シーケンシャル(ターミナル、シリアル、サウンド)
  • ブロックデバイス(block device):固定サイズブロック、ランダムアクセス(ディスク、SSD)
  • ネットワークデバイス(net device):パケット(NIC)。/dev に現れない、特別扱い。

デバイスファイル

Unixでは全てがファイル。/dev/ に:

/dev/sda, /dev/sda1     SATA/SCSI/SAS/USB接続ディスク
/dev/nvme0n1, /dev/nvme0n1p1  NVMe
/dev/tty0〜tty6仮想コンソール
/dev/ttyS0, /dev/ttyUSB0シリアル、USBシリアル
/dev/nullビットバケット
/dev/zero無限の0
/dev/random, /dev/urandom暗号論的乱数
/dev/input/eventN入力デバイス
/dev/fb0フレームバッファ
/dev/dri/card0           DRM(Direct Rendering Manager、GPU)
/dev/snd/                ALSAサウンド

udevとsysfs

ホットプラグイベント(USB挿入、デバイス電源投入)を検知し、/dev ノード作成・パーミッション設定・ユーザ通知。

sysfs(/sys)がデバイスツリーを表現し、カーネル↔ユーザ空間の構造化インターフェースとなる。

Linuxのドライバモデル

【図9】Linuxドライバモデル階層:

graph TB US["ユーザ空間 / open, read, write, ioctl, mmap"] VFS["VFS / ブロック層 / ネットワークスタック"] DD["デバイスドライバ / file_operations / block_device_operations"] BUS["バスドライバ (PCI, USB, I2C, SPI)"] HW["ハードウェア"] US -.syscall.-> VFS VFS --> DD DD -.ハードウェア操作.-> BUS BUS --> HW

カーネルモジュール

Linuxの多くのドライバは .ko ファイルとしてビルドされ、起動後に動的にロード可能。

lsmod                # ロード中モジュール
modinfo <mod>        # モジュール情報
modprobe <mod>       # 依存関係解決してロード
rmmod <mod>          # アンロード
dmesg | tail         # ロード時のログ

割り込み処理

上位ハーフ(Top Half)

割り込みハンドラ本体。割り込み禁止で動く最小限の処理。レジスタ読み、ハード状態クリアのみ。

下位ハーフ(Bottom Half)

時間のかかる処理は後で実行。以下のメカニズム:

  • Softirq:静的、高速、ネットワーク処理など
  • Tasklet:softirq上の軽量API、廃止予定
  • Workqueue:kworkerカーネルスレッドで実行、スリープ可能

MSI / MSI-X(Message Signaled Interrupts)

PCI Express時代の割り込み。専用ライン不要、デバイスが特定メモリアドレスに書き込むことで割り込み通知。ベクタ数が多く、マルチコア負荷分散に適する。

DMA(Direct Memory Access)

CPUを介さずにデバイスがメモリに直接R/W。大容量転送でCPU負荷を回避。

IOMMU(Intel VT-d、AMD-Vi、ARM SMMU)でDMAにも仮想アドレスを使い、保護・仮想化を実現。


ネットワーキング

ネットワークスタック

OSI / TCP/IPの5層モデル:

【図10】TCP/IPネットワーク階層:

graph TB L7["L7アプリケーション層 / HTTP, DNS, SSH, SMTP"] L4["L4トランスポート層 / TCP, UDP, QUIC"] L3["L3ネットワーク層 / IPv4, IPv6, ICMP"] L2["L2データリンク層 / Ethernet, Wi-Fi"] L1["L1物理層 / 銅線、光ファイバ、電波"] L7 --> L4 --> L3 --> L2 --> L1

ソケットAPI

Berkeley Sockets(1983年のBSD 4.2から)が業界標準。

// TCPサーバの骨格
int srv = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
struct sockaddr_in addr = {
    .sin_family = AF_INET,
    .sin_port = htons(8080),
    .sin_addr.s_addr = INADDR_ANY
};
bind(srv, (struct sockaddr*)&addr, sizeof(addr));
listen(srv, 128);

while (1) {
    int cli = accept(srv, NULL, NULL);
    char buf[4096];
    ssize_t n = read(cli, buf, sizeof(buf));
    write(cli, buf, n);
    close(cli);
}

LinuxのTCP/IPスタック

カーネルnet/ipv4/, net/ipv6/, net/core/ にある。主要コンポーネント:

  • sk_buff(socket buffer, “skb”):パケットの内部表現。
  • Qdisc(Queuing Discipline):送信キュー管理(fq_codel, cake, htb)。
  • Netfilter:パケットフィルタリングフック(iptables, nftables)。
  • Traffic Control (tc):帯域制御、シェーピング、ポリシング。
  • ConntrackNAT、接続追跡。
  • XFRM:IPsec。

TCPの制御アルゴリズム

輻輳制御が実装で選択可能:

  • Reno / NewReno:古典
  • Cubic(Linuxデフォルト2008〜)
  • BBR(Google, 2016〜):帯域・RTTベース、広く採用
  • BBRv2, BBRv3
  • Vegas, Westwood, Hybla, HSTCP
sysctl net.ipv4.tcp_congestion_control    # 確認
sysctl -w net.ipv4.tcp_congestion_control=bbr  # 設定

eBPF(extended Berkeley Packet Filter)

Linuxカーネルに小さな「安全な仮想マシン」を埋め込み、ユーザ空間のC/Rustプログラムをカーネル内で実行する革新的機構。

仕組み

  • 検証器(Verifier):実行前にコードを静的解析、無限ループ・カーネルパニック防止
  • JIT コンパイルeBPF バイトコード → ネイティブマシン語(x86-64, ARM, RISC-V対応)
  • メモリモデル:スタック512 bytes固定、マップ(共有メモリ)、リングバッファ

主な用途と実装

  • パケットフィルタリング:cgroup eBPF (socket filter)、tc eBPF (traffic control、iptablesの現代版)
  • XDP(eXpress Data Path):NIC ドライバ直下で実行(カーネルバイパス)、低遅延ルータ・ファイアウォール。フレーム単位の判定(XDP_DROP/XDP_PASS/XDP_TX)
  • トレーシング:kprobe (カーネル関数フック)、uprobe (ユーザアプリフック)、tracepoint (静的マーカー)。ツール:bpftrace, bcc, BPFtool
  • セキュリティ:Seccomp BPF (syscall フィルタ)、Cilium (Kubernetes ネットワークセキュリティ、ホストファイアウォール)、Falco (脅威検知)
  • 可観測性:Pixie (自動コンテナプロファイリング)、Parca (CPU プロファイリング)、Pyroscope (分散トレーシング)

eBPF によるシステムの透視(性能低下最小):

sudo bpftrace -e 'tracepoint:syscalls:sys_enter_open* { @[comm] = count(); }'
# open syscall の呼び出し元プロセスをリアルタイム集計
SEC("xdp")
int xdp_drop_icmp(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end) return XDP_ABORTED;
    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end) return XDP_ABORTED;
    if (ip->protocol == IPPROTO_ICMP) return XDP_DROP;
    return XDP_PASS;
}

名前空間とネットワーク分離

Linuxnetwork namespace により、プロセス群ごとに独立したNIC、ルーティングテーブル、iptablesを持てる。DockerKubernetes、VPNクライアント(Tailscale, WireGuard)で使用。

ip netns add myns
ip netns exec myns ip link   # 分離されたloのみ見える
ip link add veth0 type veth peer name veth1
ip link set veth1 netns myns

QUICとHTTP/3

  • QUIC(RFC 9000, 2021):UDPベース、TLS 1.3統合、0-RTT、head-of-line blocking除去
  • HTTP/3(RFC 9114, 2022):QUIC上のHTTP
  • Linuxカーネルは2024年からQUIC対応を段階的に導入

セキュリティ

ヒント

OSのセキュリティは「多層防御(defense in depth)」の原則に立っています。認証・認可・サンドボックス・暗号化・監査を重ねがけして、どこかが破られても他で食い止めます。

OSのセキュリティは多層防御(defense in depth)が原則です。単一の防壁に依存せず、複数の独立した層で攻撃者を遅延・検出します。

基本的脅威モデル

  • 不正アクセス:許可されない読み書き・実行
  • 権限昇格:一般ユーザからrootへの昇格、サンドボックス脱出
  • 機密性破壊:データの盗難、パスワード漏洩
  • 完全性破壊:データ・コード改ざん、rootkit
  • 可用性破壊:DoS、クラッシュ、資源枯渇
  • 否認:操作の否認(監査ログで防御)

アクセス制御モデル

DAC(Discretionary Access Control)

Unixの rwx パーミッションが典型。所有者がアクセス権を自由に設定できる。

flowchart TB F["-rw-r--r-- 1 alice users 4096 Apr 10 12:34 file.txt"] F --> T["file type"] F --> O["所有者権限"] F --> G["グループ権限"] F --> U["その他ユーザ権限"] F --> OW["所有者: alice"] F --> GR["グループ: users"]

拡張:ACL(setfacl, getfacl)で個別ユーザ・グループに細かい権限付与。

MAC(Mandatory Access Control)

システム管理者のポリシーが強制され、所有者でも変更できない。

  • SELinux(NSA開発、Red Hat系):タイプ強制、ロールベース、マルチレベル
  • AppArmor(Canonical, SUSE):パスベース、プロファイル単位、学習モードあり
  • TOMOYO Linux:パスベース、日本NTT開発
  • SMACK:シンプル、Tizenで使用

RBAC(Role-Based Access Control)

ロールを介して権限を管理。SELinuxの一部、Kubernetes RBACなど。

Capabilities

Linuxでは伝統的な「root or not」を分解し、個別権限(CAP_NET_BIND_SERVICE、CAP_SYS_ADMIN、CAP_CHOWN、CAP_KILLなど41種類)に分離。必要なcapabilityのみを付与できる。

setcap 'cap_net_bind_service=+ep' /usr/bin/myserver
# root権限なしで <1024のポートにバインド可

サンドボックス機構

seccomp BPF

許可するシステムコールをBPFフィルタで制限。許可外のシステムコールを呼ぶとカーネルがSIGKILL / SIGSYSで強制終了。Chrome、Dockersystemd、Firefoxで使用。

struct sock_filter filter[] = {
    BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)),
    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_execve, 0, 1),
    BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
    BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

名前空間(Linux namespaces)

プロセスごとに独立した「見える世界」を提供。コンテナの基盤。

名前空間 分離対象 関連syscall
PID プロセスID空間 clone(CLONE_NEWPID)
NET ネットワーク clone(CLONE_NEWNET)
MNT マウントポイント clone(CLONE_NEWNS)
UTS ホスト名、ドメイン名 clone(CLONE_NEWUTS)
IPC System V IPC、POSIX msgqueue clone(CLONE_NEWIPC)
USER UID/GID、capability clone(CLONE_NEWUSER)
CGROUP cgroupビュー clone(CLONE_NEWCGROUP)
TIME boot time, monotonic time clone(CLONE_NEWTIME)

Landlock(Linux 5.13〜)

アプリケーション自身が「私はこれ以上のファイルアクセスは不要」と宣言できる、unprivileged sandbox。

macOS Sandbox(SBPL)

Scheme風DSLでポリシーを記述。/System/Library/Sandbox/Profiles/ 以下にOS全体のプロファイル。Mac App Storeアプリは必須。

Windows AppContainer、Integrity Level

UWPアプリケーション、ブラウザ(Edge)のレンダラプロセスで使われる。

メモリ保護機構

ASLR(Address Space Layout Randomization)

スタック、ヒープ、共有ライブラリ、実行ファイルのロードアドレスをランダム化。攻撃者がROPガジェットのアドレスを事前に知ることを困難に。

Linux: /proc/sys/kernel/randomizevaspace/proc/sys/kernel/randomize_va_space (0/1/2) Windows: Vista以降デフォルト macOS: デフォルト有効

KASLR(Kernel ASLR)

カーネル自体のロードアドレスをブート毎にランダム化。Meltdown攻撃で回避されたため、KPTI(Kernel Page Table Isolation) と組み合わせる。

DEP / NX(Data Execution Prevention / No-eXecute)

データ領域(スタック、ヒープ)を実行不可にマーク。スタックバッファオーバーフローからのシェルコード実行を防止。x86のNXビット、ARMのXNビット。

Stack Canary / Stack Protector

関数の戻りアドレスの前に「カナリア値」を置き、関数終了時にチェック。バッファオーバーフローを検出。GCCの -fstack-protector-strongWindows/GS

CFI(Control Flow Integrity)

間接ジャンプ・間接コールが合法的なターゲットであることを検証。Clang CFI、Intel CET(Control-flow Enforcement Technology)、ARM BTI(Branch Target Identification)、ARM PAC(Pointer Authentication)。

SMEP / SMAP(Supervisor Mode Execution/Access Prevention)

カーネルモードからユーザ空間のコードを実行/データを読むことを禁止。ret2usr攻撃の防止。

認証

  • パスワード:shadowファイル(/etc/shadow)にソルト付きハッシュ(SHA-512、yescrypt)
  • PAM(Pluggable Authentication Modules):統一認証基盤
  • LDAP / Active Directory:集中認証
  • Kerberos:チケットベースSSO
  • TPM(Trusted Platform Module):ハードウェア鍵ストア
  • FIDO2 / WebAuthn:フィッシング耐性、パスキー
  • Biometrics:指紋(Touch ID、Windows Hello)、顔認証

暗号化

フルディスク暗号化

  • Linux: LUKS + dm-crypt(AES-XTS)
  • Windows: BitLocker(AES-XTS、TPMと連携)
  • macOS: FileVault(AES-XTS)
  • iOS: Data Protection(per-file key、ハードウェアエンクレーブ)

ファイルシステム暗号化

  • fscrypt(Linux ext4, F2FS):per-file、per-directory
  • eCryptfs(スタック型)
  • APFS encryption(macOS、per-volume)
  • EFS(NTFS、per-file)

セキュアブート

UEFI Secure Boot:ブートローダ、カーネルが認証された署名鍵で署名されているかを検証。

チェーン:UEFI → Platform Key (PK) → KEK → db → Bootloader → KernelLinuxでは shim がMicrosoft署名を受け、GRUBカーネルへ署名チェーンを伸ばす。

Measured Boot:各段階のハッシュをTPMのPCRに記録。後で検証可能。

カーネルエクスプロイト対策

  • KASLR + FGKASLR:関数ごとにランダム化
  • stack canary
  • SLAB_HARDENED / freelist randomization
  • heap spray防止(slab cookie)
  • signed modulesカーネルモジュールの改ざん防止
  • lockdown mode:ロックダウンカーネル(IMA/EVMによる)
  • CONFIG_FORTIFY_SOURCE
  • KSPP(Kernel Self-Protection Project) による継続的強化

仮想化ベースセキュリティ

  • Intel SGX(Enclave):分離された実行環境、ただし2022年に段階的廃止
  • Intel TDX(Trust Domain Extensions):VM単位の機密計算
  • AMD SEV/SEV-ES/SEV-SNP暗号化VMメモリ
  • ARM CCA(Confidential Compute Architecture):Realm
  • Windows VBS / Credential Guard:Hyper-Vで分離したセキュリティVM
  • Apple Secure Enclave:T2チップ、Mシリーズ内蔵

仮想化

ヒント

仮想化は「1台の物理マシンで複数のOSを同時に動かす」技術です。クラウドの基盤はすべてこれです。コンテナよりも分離が強く、オーバーヘッドは少し大きくなります。

仮想化 vs コンテナの比較

項目 仮想化 コンテナ
分離レベル 完全(別カーネル 論理的(共有カーネル
起動時間 数秒 数ミリ秒
メモリ効率 低(ゲストOS込)
同一ホスト上での数 数十個 数千個
OS 多様性 高(Windows/Linux/BSD可) Linux が中心
デバッグ / アクセス ゲストOSに完全アクセス 限定的(namespace隔離)

仮想化の種類

Type-1ハイパーバイザ(Bare Metal)

ハードウェア直上で動作。OSなしで動く。

  • VMware ESXi:エンタープライズデファクト
  • Microsoft Hyper-VWindows Server統合、Azure基盤
  • Xen:AWS EC2初期、現在はNitroに移行、NetBSD由来
  • KVM(Kernel-based Virtual Machine):Linuxカーネルに統合、Type-1相当
  • Proxmox VEoVirtOpenStack(管理基盤)

Type-2ハイパーバイザ(Hosted)

ホストOS上で動作。

  • VMware Workstation / Fusion
  • Oracle VirtualBox
  • Parallels Desktop(Mac)
  • QEMU(ユーザモード)
  • UTM(QEMUフロントエンド、macOS)

マイクロVM (Lightweight VMs)

コンテナの速度とVM の分離を両立する新世代技術。クラウドネイティブ向け。

  • Firecracker(AWS):Linux カーネル 5.10+、最小メモリ 3MB、起動 125ms、Kubernetes Pod 代替、Lambda/Fargate 基盤
  • Kata ContainersOCI 準拠、gVisor よりもセキュア分離、gRPC 経由で kubelet と連携
  • gVisor(Google):Go 実装、ユーザモード Linux(umode Linux)、syscall インターセプト

マイクロVM の用途:

  • コンテナの「隣人との干渉」を排除(noisy neighbor 問題回避)
  • セキュリティ境界の強化(malicious container ハイジャック防止)
  • 複数テナント環境の確実な分離(multi-tenant FaaS

仮想化技術の分類

完全仮想化(Full Virtualization)

ゲストOSは未改変で動く。x86は元来仮想化困難な17個の特権命令があったが、バイナリトランスレーション(VMware初期)、次いでハードウェア支援(Intel VT-x、AMD-V)で解決。

準仮想化(Paravirtualization)

ゲストOSが「自分はVM上にいる」と認識し、ハイパーバイザ用API(hypercall)を使う。Xen PVが代表。

ハードウェア支援仮想化

  • Intel VT-x (VMX):ルート / ノンルートモード、EPT(Extended Page Table)
  • AMD-V (SVM):NPT(Nested Page Table)
  • ARM Virtualization Extensions:EL2
  • RISC-V H extension

KVMのアーキテクチャ

【図11】KVM仮想化スタック:

graph TB Guest["Guest OS / Linux, Windows, BSD, ..."] QEMU["QEMU / デバイスエミュレーション(ユーザ空間)"] KVM["KVM(Linuxカーネルモジュール) / VM実行制御、EPT/NPT管理"] HW["ホストCPUハードウェア / Intel VT-x / AMD-V"] Guest --> QEMU QEMU -.dev/kvm ioctl.-> KVM KVM -.VT-x / AMD-V.-> HW

メモリ仮想化

  • シャドウページテーブル:VMMがゲストPTのシャドウを維持(古い手法)
  • EPT/NPT:二段変換、ハードウェア支援(現行)
  • Balloon driver:ゲストから「不要メモリ」を回収
  • KSM(Kernel SamePage Merging):ホストで同一内容ページ統合
  • Memory overcommitment:ゲスト合計 > 物理

CPU仮想化

  • VMCS(VM Control Structure):VM状態を保持
  • VM-Entry / VM-Exit:ホスト ↔ ゲスト遷移
  • CPU pinning:仮想CPUを物理コアに固定
  • Nested virtualization:VMの中にVM

I/O仮想化

  • Emulated devices(e1000, rtl8139):遅い
  • Virtio準仮想化、virtio-net, virtio-blk, virtio-scsi, virtio-fs
  • PCI passthrough:デバイスを直接ゲストに割り当て(IOMMU必須)
  • SR-IOV:1物理NICを複数VF(Virtual Function)に分割

マイクロVMと現代的仮想化

VM起動時間を秒以下にし、関数実行や高密度サンドボックスに使う:

  • Firecracker(AWS、Rust製):Lambda、Fargateの基盤。125 msで起動
  • Cloud Hypervisor(Intel、Rust製)
  • Kata Containers:Docker/Kubernetesで軽量VMをコンテナ代わりに
  • Apple Hypervisor.frameworkMicrosoft Hypervisor Platform

コンテナ技術

ヒント

コンテナは「軽量な仮想化」です。ホストOSのカーネルを共有するため、仮想マシンより起動が速く、1台で数百〜数千動かせます。DockerとKubernetesが現代のクラウドの事実上の標準です。

コンテナとは

プロセス単位の軽量仮想化。完全なゲストOSなし、ホストカーネル共有。起動数十ミリ秒、オーバーヘッド最小。

Linuxコンテナの基盤

1. 名前空間(Namespaces)

(セキュリティ章参照)プロセスから「見える世界」を制限。

2. cgroups(Control Groups)

CPU、メモリ、I/O、ネットワーク、PID数、デバイスアクセスを制限・計測。

  • cgroup v1(階層ごとに別マウント):古い
  • cgroup v2(統一階層):現行、systemd, Kubernetesで推奨
# cgroup v2でのmemory制限
echo "1G" > /sys/fs/cgroup/mygroup/memory.max
echo $ > /sys/fs/cgroup/mygroup/cgroup.procs

3. Capabilities

(セキュリティ章参照)root権限を分解。

4. Seccomp

(セキュリティ章参照)syscallフィルタ。

5. Union Filesystems(OverlayFS, aufs, btrfs subvol)

レイヤー化されたファイルシステム。Docker imageのbase/layer/containerの基盤。

OCI(Open Container Initiative)標準

  • Runtime Specificationコンテナの実行方法(runc、crun、youki、runsc/gVisor)
  • Image Specification:イメージフォーマット(config.json + layers)
  • Distribution Specification:レジストリAPI

コンテナランタイムの階層

【図12】コンテナランタイムの階層:

graph TB Orch["オーケストレータ / Kubernetes, Nomad, Swarm"] HiRT["高レベルランタイム / containerd, CRI-O, Podman"] LoRT["低レベルランタイム / runc, crun, youki (Rust) / runsc (gVisor), kata-runtime"] Kernel["Linuxカーネル / namespaces, cgroups, seccomp"] Orch -.CRI.-> HiRT HiRT -.OCI Runtime Spec.-> LoRT LoRT -.clone, unshare, etc.-> Kernel

Docker

2013年、Solomon HykesらがdotCloudで開発。コンテナを「クラウド時代のデプロイメント単位」として普及させた。

主要機能:

  • Dockerfile:イメージビルドレシピ
  • Image layers:差分ベース、共有
  • Docker Hub:パブリックレジストリ
  • Docker Compose:複数コンテナのオーケストレーション
  • Docker Swarm:クラスタリング(Kubernetesに市場で敗北)

Kubernetes

Googleの内部システムBorg/Omegaに触発され、2014年に発表。現在CNCFが保守する事実上のクラウドオーケストレータ標準。

【図16】Kubernetes主要コンポーネント:

graph TB subgraph CP["Control Plane"] API["kube-apiserver / REST API、全体の中心"] ETCD["etcd / 分散KVストア、状態保持"] SCH["kube-scheduler / Pod → Node配置"] CM["kube-controller-manager / Deployment, ReplicaSet等"] CCM["cloud-controller-manager"] end subgraph WN["Worker Node"] KBL["kubelet / Pod管理、CRI経由"] KP["kube-proxy / Service実装"] RT["Container Runtime / containerd / CRI-O"] end KBL -.通信.-> API KP -.通信.-> API KBL --> RT

リソース種別:Pod, ReplicaSet, Deployment, StatefulSet, DaemonSet, Job, CronJob, Service, Ingress, ConfigMap, Secret, PersistentVolume, PersistentVolumeClaim, Namespace, Role, ClusterRole, NetworkPolicyなど。

代替・周辺

  • Podman:デーモンレス、rootless、systemd統合
  • LXC / LXDOSコンテナ(≒軽量VM)、Canonical
  • rkt:CoreOS、終息
  • Nixery, Bazel:再現可能ビルド
  • gVisor(Google):ユーザ空間カーネルセキュリティ特化
  • Kata Containers:VMと見分けつかない強い分離

デスクトップOSの詳細比較

ヒント

世界で使われているデスクトップOSは事実上Windows、macOS、Linuxの3つです。それぞれ設計哲学・ターゲット層・パッケージ管理が大きく異なります。

Windows

Microsoftが1985年にMS-DOS上のシェルとして発売。1995のWindows 95で大衆化、2000年のWindows NTベース化でモダンOSに。

Windowsのエディションと歴史

【図17】Windows系統図:

graph LR W["Windows系統"] W --> N9x["9x系(終了)"] W --> NT["NT系(現行)"] W --> Svr["Server系"] W --> Emb["組み込み"] W --> Mob["モバイル(消滅)"] N9x --> W95["Windows 95 (1995)"] N9x --> W98["Windows 98"] N9x --> WME["Windows ME"] NT --> NT31["Windows NT 3.1 (1993)"] NT --> W2K["Windows 2000"] NT --> XP["Windows XP (2001, 長寿命)"] NT --> Vista["Windows Vista"] NT --> W7["Windows 7 (2009, 最人気)"] NT --> W8["Windows 8 / 8.1"] NT --> W10["Windows 10 (2015)"] NT --> W11["Windows 11 (2021)"] Svr --> Srv["Windows Server 2003/2008/2012/2016/2019/2022/2025"] Emb --> Iot["Windows Embedded/IoT"] Mob --> WP["Windows Phone 7/8/10"]

Windows 11の技術的特徴

  • NT kernel(ntoskrnl.exe):ハイブリッドカーネル
  • WSL2:軽量Hyper-V VMでLinuxカーネル統合
  • DirectX 12 Ultimate、DirectStorage:GPU最適化
  • Windows Package Manager (winget)
  • WinGet、PowerShell 7、Windows Terminal:モダンCLI
  • TPM 2.0 + Secure Boot必須:ハードウェアベースセキュリティ
  • ARM64対応強化:Qualcomm Snapdragon X Elite
  • Copilot統合:AIアシスタント
  • Plutonセキュリティプロセッサ

Windowsファイルシステム

  • FAT12/16/32/exFAT:互換性、USBメモリ、SDカード
  • NTFS:メインシステム、ACL、EFS、ジャーナリング、VSS
  • ReFS(Resilient File System):Windows Server向け、破損耐性、チェックサム

macOS

NeXTSTEP(1989)→ Rhapsody → Mac OS X 10.0(2001)→ macOS Sequoia 15(2024)と進化。

macOSの技術スタック

【図13】macOS技術スタック:

graph TB UI["ユーザインターフェース / Aqua, SwiftUI, AppKit (Cocoa), UIKit"] AS["アプリケーションサービス / Core Animation, Core Data, Core Text, ImageKit"] GM["グラフィックス・メディア / Quartz, Metal, Core Graphics, AVFoundation, AudioToolbox"] SI["システムインターフェース / Foundation, libSystem (libc, libm, libpthread)"] K["カーネル (XNU) / Mach + BSD + I/O Kit"] UI --> AS --> GM --> SI --> K

Apple Silicon移行

2020年M1発表以降、IntelからApple設計ARM64チップへ完全移行。

  • M1 → M1 Pro/Max/Ultra → M2 → M3 → M4(2024)
  • Rosetta 2:Intelバイナリの動的バイナリ翻訳、ほぼネイティブ性能
  • ユニファイドメモリ:CPU/GPU/Neural Engineが同一RAMを共有
  • Secure Enclave:T2チップを統合
  • Virtualization.framework, Hypervisor.framework

ファイルシステム:APFS

2017年のmacOS High SierraでHFS+ を置換。

  • Copy-on-Write
  • スナップショット、Time Machine統合
  • Native encryption
  • Space sharing(複数ボリュームがプールを共有)
  • Crash protection
  • iOS/iPadOS/tvOS/watchOSでも使用

Linuxデスクトップ

デスクトップ市場ではWindowsmacOSに比べると少数派だが、開発用途、研究用途、Steam Deck(ArchベースSteamOS)などの登場で注目度は高まっている。

デスクトップ環境

DE ベース 特徴
GNOME GTK ミニマル、Waylandネイティブ、Mutter
KDE Plasma Qt 高カスタマイズ、高機能
XFCE GTK 軽量
LXQt Qt 超軽量
Cinnamon GTK Linux Mint製、伝統的
MATE GTK GNOME 2フォーク
Budgie GTK 洗練されたデザイン
COSMIC Rust/Iced System76、次世代
Pantheon GTK elementary OS
Hyprland, Sway wlroots タイル型Wayland

表示サーバ

  • X11 (X Window System):1984年、レガシーだがまだ主流
  • Wayland:2008年、モダン、X11置換進行中
  • Mir:Canonical、一時期推奨、現在は組み込み特化

三大OSの決定的違い

ファイル階層

概念 Windows macOS Linux
ルート C:\ / /
ユーザホーム C:\Users\alice /Users/alice /home/alice
一時 C:\Windows\Temp, %TEMP% /tmp, $TMPDIR /tmp
プログラム C:\Program Files /Applications /usr/bin, /opt
設定 レジストリ, %APPDATA% ~/Library/Preferences /etc, ~/.config
ログ Event Viewer ~/Library/Logs, /var/log /var/log, journald
パス区切り \ / /
ケース 非感度 非感度(オプションで感度) 感度あり

パッケージ管理

OS システム サードパーティ
Windows winget, MSIX Chocolatey, Scoop, Microsoft Store
macOS App Store Homebrew, MacPorts, Nix
Linux apt (Debian), dnf (RH), pacman (Arch), zypper (SUSE), emerge (Gentoo), nix (NixOS), portage, xbps (Void), apk (Alpine) Flatpak, Snap, AppImage, pip, npm

シェル

OS デフォルト その他利用可
Windows 11 PowerShell 7 cmd, Git Bash, WSL (bash)
macOS 10.15+ zsh bash, fish, tcsh
多くのLinux bash zsh, fish, dash, nushell

使用シーンの適性

  • Windows:ゲーミング、エンタープライズ、MS Office、Adobe、DirectXゲーム
  • macOS:クリエイティブ(Logic Pro, Final Cut)、iOS開発、モバイルファースト、BSD/Unix系開発、統合された体験
  • Linux:サーバ、Web開発、データサイエンス、カーネル研究、クラウド、組み込み、カスタマイズ性重視

モバイルOS

ヒント

モバイルOSはAndroidとiOSが中心です。AndroidはLinuxカーネルベース、iOSはXNUベースで、どちらも省電力・セキュリティ・バッテリー管理に特化した設計です。

Android

Google主導、Open Handset Alliance発足(2007)、2008年にHTC Dream発売。現在は世界で最も広く使われているモバイルOSの一つである。

Androidのアーキテクチャ

【図14】Androidアーキテクチャ:

この図では、Androidが「アプリ層 → フレームワーク → ランタイム / ネイティブライブラリ → HAL → Linuxカーネル」という多層構造で成り立つ点を見る。

graph TB App["Androidアプリケーション (APK) / Gmail, Maps, YouTube, サードパーティ"] FW["Java API Framework / Activity, Service, ContentProvider, View / Notification, Package, Resource Manager"] Native["Native C/C++ Libs / Bionic libc, SQLite, WebKit / OpenGL ES, Media Framework"] ART["Android Runtime (ART) / Dalvikの後継、AOT + JIT、ガベコレ"] HAL["Hardware Abstraction Layer (HAL) / Audio, Bluetooth, Camera, Sensors, Radio"] Kernel["Linux Kernel (LTS + Android patches) / Binder IPC、低メモリキラー、ANR、SELinux / wakelocks、ashmem、gralloc"] App --> FW FW --> Native FW --> ART Native --> HAL ART --> HAL HAL --> Kernel

Androidの特徴

  • Binder IPC:マイクロカーネル風の高速IPC、全システムサービスの通信基盤
  • Zygote:アプリ起動高速化のため、ARTのwarmコピーをfork
  • Android Runtime (ART):Dalvikを5.0 (Lollipop) で置換、AOT + プロファイルガイドJIT
  • SELinux Enforcing:5.0から必須
  • Scoped Storage(Android 11+):アプリごとのストレージ分離
  • Project Mainline:モジュール式システムコンポーネント更新
  • Generic Kernel Image (GKI):ベンダとのABI分離

ここで ANRApplication Not Responding の略で、アプリが一定時間応答しないときの警告である。wakelock は端末を不用意にスリープさせないための仕組み、gralloc はGPU/表示系バッファの割り当て基盤である。GKIAndroidカーネルの共通部分を標準化し、端末ベンダ固有部分と分離しやすくする取り組みを指す。

Androidバージョン

バージョン コードネーム
4.0 Ice Cream Sandwich 2011
4.4 KitKat 2013
5.0 Lollipop 2014
6.0 Marshmallow 2015
7.0 Nougat 2016
8.0 Oreo 2017
9.0 Pie 2018
10 (英語圏外ドロップ) 2019
11 2020
12/12L 2021/2022
13 2022
14 2023
15 2024
16 2025

AOSPと派生

  • AOSP(Android Open Source Project):ベース
  • Google Android:GMS(Google Mobile Services)+ AOSP
  • Samsung One UIOnePlus OxygenOSXiaomi HyperOSOPPO ColorOSHUAWEI EMUI/HarmonyOS:カスタムROM
  • LineageOS、GrapheneOS、CalyxOS:プライバシー・カスタム志向
  • Amazon Fire OSKai OS:分岐

iOS / iPadOS

Appleが2007年発表、iPhone専用からiPad(iPadOS 13+)、Apple Watch(watchOS)、Apple TV(tvOS)、Vision Pro(visionOS)へと拡張。

iOSのアーキテクチャ

【図15】iOSアーキテクチャ:

graph TB CT["Cocoa Touch / UIKit, SwiftUI, Foundation, MapKit, GameKit"] MD["Media / Core Animation, Metal, AVFoundation"] CS["Core Services / Core Data, CloudKit, Core Location"] CO["Core OS / libSystem, Security, drivers"] K["XNU Kernel / Mach + BSD + IOKit + iOS-specific additions"] CT --> MD --> CS --> CO --> K

iOSのセキュリティ機構

  • Secure Boot Chain:Boot ROM → LLB → iBoot → Kernel、各段階で署名検証
  • Secure Enclave Processor (SEP):指紋、Face ID、鍵保管
  • Data Protection:per-file AES-256暗号化、4段階保護クラス
  • Code Signing:全実行コードはApple署名が必要
  • Sandboxing:全アプリは厳格なサンドボックス内で動作
  • App Transport Security (ATS):TLS強制
  • Privacy Controls:アプリごとの権限(位置、写真、マイク、Bluetooth、トラッキング)
  • Jailbreak:Secure Bootチェーンを破る攻撃、コミュニティは衰退

iPadOSの独自性

  • Stage Manager:ウィンドウマネージャ
  • Scribble、Apple Pencil統合
  • マウス/トラックパッド対応
  • Swift Playgroundsでのアプリ開発
  • 外部ディスプレイ対応

HarmonyOS、OpenHarmony

Huaweiが米国制裁後に独自開発。初期はAndroidフォーク、現在は完全独立(LiteOS / Linuxカーネル、マイクロカーネル設計)。中国市場で急成長。

Tizen、KaiOS

  • Tizen:Samsungテレビ、ウェアラブル
  • KaiOS:フィーチャーフォン(Jio Phone)、低スペック市場

リアルタイムOSと組み込みOS

リアルタイムOS(RTOS)とは

時間制約が正しさの一部となるシステム向けOS。「正しい結果を出す」だけでなく「決められた時間内に出す」が要件。

分類

  • ハードリアルタイム:期限超過 = システム失敗。例:ABS、エアバッグ、航空機制御、心臓ペースメーカ
  • ソフトリアルタイム:期限超過 = 品質低下だが許容。例:動画再生、VoIP、ゲーム

RTOSの要件

  • 決定性:割り込み遅延、タスク切替時間が予測可能
  • 優先度ベーススケジューリング:厳密
  • 優先度継承プロトコル優先度逆転回避
  • 高速コンテキストスイッチ:μsオーダー
  • 小さなフットプリント:数KB〜数MB
  • 静的解析可能性:WCET(Worst-Case Execution Time)の見積り

主要RTOS

RTOS 開発元 用途
QNX Neutrino BlackBerry 自動車(BMW、Audi、Ford)、原発制御
VxWorks Wind River 火星探査機、B-52、F-35
FreeRTOS AWS IoT、Arduino、ESP32
Zephyr Linux Foundation IoT、ウェアラブル
RTEMS 米OAR 航空宇宙、CERN
ThreadX / Azure RTOS Microsoft IoT、産業機器
Micrium µC/OS Silicon Labs 組み込み全般
Mbed OS Arm ARMマイコン
Integrity / Integrity-178B Green Hills DO-178B認証、軍事
Contiki 無線センサネットワーク
TinyOS IoT学術
NuttX Apache ドローン(PX4)、ウェアラブル

PREEMPT_RT(Linuxのリアルタイムパッチ)

LinuxカーネルにRT性を加えるパッチセット。2005年頃からIngo Molnárらが開発し、2024年にメインラインにマージされた。

  • カーネルの多くの spinlocktspinlock_trtmutexrt_mutex に置換(優先度継承対応)
  • 割り込みをスレッド
  • RCUのRT対応
  • threadirqs機能

産業ロボット、3Dプリンタ(LinuxCNC)、オーディオワークステーション、株取引システム等で使用。

組み込みLinux

  • Yocto Project / OpenEmbedded:カスタムLinuxディストリ構築フレームワーク
  • Buildroot:軽量、シンプル
  • Ubuntu Core:スナップベース、IoT
  • Raspberry Pi OS(旧Raspbian):Pi公式
  • OpenWrt / LEDE:ルータ向け

分散OS・クラウドOS

分散OSの系譜

1980〜90年代に多くの分散OSが研究された。

  • Amoeba(Tanenbaum):マイクロカーネル、ケーパビリティ
  • Plan 9 from Bell Labs(Unixの設計者たち):「全てはファイル」を徹底
  • Inferno(Plan 9継承、Java代替を狙った)
  • SpriteLOCUSMach(CMU、NeXT経由でmacOSへ)

これらは商用的成功は限定的だったが、概念は現代のクラウド・分散システムに継承。

クラウドOS / データセンターOS

  • Kubernetes:事実上のクラウドOS、宣言的API
  • HashiCorp Nomad:軽量、非K8s
  • Mesos(D3OS):Twitter、Uber、Airbnbで使用、現在は衰退
  • Google Borg(内部):K8sの先祖
  • Apache YARN / HDFS:Hadoopエコシステム
  • AWS Firecracker + Lambda/Fargate:サーバレス
  • Nomad、Azure Service Fabric、Google Anthos

サーバレス / FaaS

関数単位で実行単位を抽象化。コードだけアップロードし、OSやインフラは管理しない。

  • AWS Lambda(2014):代表的な初期サーバレス基盤
  • Google Cloud Functions, Cloud Run
  • Azure Functions
  • Cloudflare Workers(V8 Isolateベースのエッジ実行環境)
  • Knative(Kubernetes上のサーバレス)

OSのパフォーマンス分析とチューニング

4つのゴールデンシグナル

  • レイテンシ(Latency):1リクエストの遅延
  • トラフィック(Traffic):単位時間あたりの要求数
  • エラー率(Errors)
  • 飽和度(Saturation):リソース使用率、キュー深さ

USEメソッド(Brendan Gregg)

すべてのリソースについて:

  • Utilization:使用率
  • Saturation:待ち行列
  • Errors:エラー数

Linuxの観測ツール

CPU/プロセス
  top, htop, atop, btop      — 概観
  ps, pgrep                  — プロセスリスト
  pidstat                    — プロセス別統計
  mpstat                     — CPU別統計
  uptime                     — load average
  vmstat                     — 仮想メモリ統計
  perf                       — ハードウェアカウンタ、CPUプロファイル
  ftrace                     — カーネルトレース
  eBPF (bpftrace, bcc tools) — 万能トレース

メモリ
  free, vmstat
  /proc/meminfo, /proc/buddyinfo, /proc/slabinfo
  slabtop
  pmap, smem
  numastat

ディスク
  iostat, iotop
  dstat
  ioping, fio
  blktrace

ネットワーク
  ss (socket stats)
  ip route, ip addr
  ifstat, nstat
  tcpdump, tshark
  iperf3, netperf
  ethtool

高度
  perf top, perf record, perf report, perf trace
  bpftrace
  SystemTap (廃れつつある)
  LTTng

Brendan Greggの60秒分析

1.  uptime
2.  dmesg | tail
3.  vmstat 1
4.  mpstat -P ALL 1
5.  pidstat 1
6.  iostat -xz 1
7.  free -m
8.  sar -n DEV 1
9.  sar -n TCP,ETCP 1
10. top

Linuxでの初動調査導線

Linuxの障害調査では、いきなりprofilerを回すより、まず「どの層で詰まっているか」を粗く切り分ける方が速い。たとえば次の順で見ると、CPU・メモリ・I/O・ネットワーク・サービス状態のどこに寄っているかが見えやすい。

  1. systemctl status <service> で対象サービスの生死と直近エラーを確認する
  2. journalctl -u <service> -n 100journalctl -k -n 100 で、アプリログとカーネルログを分けて読む
  3. top, vmstat 1, iostat -xz 1, ss -tulpn で資源の詰まり方を把握する
  4. /proc/<pid>/status, /proc/<pid>/smaps, /proc/<pid>/fd で個別プロセスの実態を見る
  5. 必要なら straceperfeBPFへ進む

この流れの利点は、「サービスが落ちているのか」「生きているが待たされているのか」「CPUバウンドなのかI/Oバウンドなのか」を、早い段階で誤らずに済むことにある。

straceperf の使い分け

Linuxでは straceperf を混同しやすいが、見ている層が違う。

  • strace システムコールの出入りを見る。openat, read, connect, futex, epoll_wait が大量に出ているか、どこで ENOENTEACCES が返っているか、といった「OSとの境界」を追うのに向く。
  • perf CPU時間がどこで使われているかを見る。関数単位のhot spot、キャッシュミス、分岐予測ミス、カーネルとユーザ空間の比率など、より性能寄りの情報に向く。
strace -p <pid>
strace -c -p <pid>
perf stat -p <pid>
perf record -g -p <pid> -- sleep 10
perf report

目安としては、

  • 「なぜ失敗しているか」「どこで待っているか」→ strace
  • 「なぜ遅いか」「どこでCPUを使っているか」→ perf

で考えると使い分けやすい。さらに深掘りが必要なら、perf で概形を見たあとにeBPF / bpftrace で局所を観測する、という順が扱いやすい。

チューニング

カーネルパラメータ

/etc/sysctl.confsysctl -w

net.core.somaxconn=65535            # TCP accept queue
net.ipv4.tcp_tw_reuse=1             # TIME_WAIT再利用
net.ipv4.tcp_fin_timeout=30
net.ipv4.ip_local_port_range=1024 65535
vm.swappiness=10                    # スワップ積極性
vm.dirty_ratio=20                   # dirtyページ上限
fs.file-max=2097152
kernel.pid_max=4194304

ulimit

ソフト / ハードリミット:

ulimit -n 65535    # file descriptor limit
ulimit -u 32768    # process limit
ulimit -s 8192     # stack size KB

/etc/security/limits.conf で永続化。

CPUガバナー

cpupower frequency-info
cpupower frequency-set -g performance  # performance, powersave, ondemand, schedutil

OSの歴史

ヒント

OSの歴史はハードウェアの進化と歩調を合わせて発展してきました。バッチ処理 → タイムシェアリング → PC → モバイル → クラウド → AI統合という大きな流れを押さえれば十分です。

OSの歴史はコンピュータハードウェアの進化と不可分です。五世代に分けて辿ります。

第0世代(1940年代後半〜1950年代前半):OSなき時代

ENIAC(1945)EDSAC(1949)UNIVAC I(1951)。プログラマが物理的にパッチボードを配線し、バイナリを手入力。オペレータが磁気テープを装填し、CPU使用率は極端に低かった。プログラム同士の切替に数時間かかることもあった。

第1世代(1950年代後半〜1960年代):バッチ処理

IBM 709, 7090、後継 IBM System/360(1964) が業界を席巻。

  • モニタプログラム:ジョブの連続実行を管理(IBSYS, FMS)
  • JCL(Job Control Language):ジョブ記述言語
  • スプーリング:Simultaneous Peripheral Operation On-Line、I/OとCPUの並行化
  • MULTICS(1964〜、MIT+Bell Labs+GE):タイムシェアリング、階層ファイルシステム、仮想メモリの先駆者
  • CTSS(MIT、1961):最初期の本格タイムシェアリングシステム
  • OS/360:System/360用、360万行コード、Fred Brooksの「人月の神話」はこの経験

第2世代(1970年代):UNIXの誕生とマイコン

UNIX:1969年Ken Thompson、Dennis Ritchie(Bell Labs)。MULTICSから撤退したチームがPDP-7で独自開発。

  • 1969: Unix第1版、アセンブリ
  • 1973: UnixをCで書き直し(初の移植性あるOS)
  • 1975: Version 6、大学へ配布開始
  • 1978: Version 7、UNIXの黄金版
  • 1977: BSD (Berkeley Software Distribution) フォーク開始
  • 1983: System V、AT&T商用Unix

BSD Unix:カリフォルニア大学バークレー校、TCP/IP、vi、csh、sendmailを産んだ。

CP/M(1974, Gary Kildall):8ビットマイコン用OS、後のDOSの原型。

Apple DOS, Apple II(1977):パーソナルコンピュータ革命。

第3世代(1980年代):PC時代

MS-DOS(1981):IBM PC用。マイクロソフトがSeattle Computer ProductsからQDOSを購入し改造。CP/M風。

Macintosh(1984):AppleがXerox Alto/PARCの研究を元に、一般消費者向けGUI OSを商用化。System 1 → System 7 → Mac OS 9。

AmigaOSAtari TOSMS OS/2(IBM+MS、後のWindows NTの土台)、Windows 1.0 (1985) → 3.0 (1990):MS-DOS上のGUIシェル

Minix(1987, Tanenbaum):教育用マイクロカーネルUNIXクローン。Linus TorvaldsがLinux作成の引き金となる。

GNUプロジェクト(1983, Richard Stallman):「自由なUnix」を目指す。GCC、Bash、Emacs、glibcを生んだが、カーネルGNU Hurdは完成せず。

第4世代(1990年代):Linux、Windows 95、Unix分散

Linux:1991年8月25日、Linus Torvaldsがcomp.os.minixに投稿した「Hello everybody out there using minix - I’m doing a (free) operating system (just a hobby…)」が始まり。1994年に1.0リリース、GPLライセンス。GNUユーザ空間と組み合わせた GNU/Linux ディストリビューション(Slackware 1993、Debian 1993、Red Hat 1994、SuSE 1994)が普及。

Windows NT 3.1(1993):Dave Cutler(VMS設計者)率いる新カーネル

Windows 95(1995)Windows 3.1 + Windows NTの融合、大ヒット。

BeOS(1995):革新的だった商用OS、Appleに買収される可能性もあったが、結局NeXTが選ばれ撤退。現代にHaikuとして継承。

Mac OS X 10.0 (2001):NeXTSTEPをベース、AppleがMach + BSD + Cocoaで完全再設計。

Java OS、JavaOS:Sunが仕掛けた「JavaベースOS」は失敗。

第5世代(2000年代〜現在):モバイル、クラウド、コンテナ、AI

2007: iPhone2008: AndroidモバイルOS時代到来。

2008: Google Chrome OS:Webベース。

2013: Dockerコンテナ大衆化。

2014: Kubernetes:クラウドオーケストレーション標準。

2020: Apple Silicon(M1):Mac完全ARM移行。

2022: Rust in LinuxLinuxカーネルに初めてC以外の言語が入る。

2023〜: AI機能のOS統合:Microsoft Copilot、Apple Intelligence、AndroidのオンデバイスAI機能などがOS体験へ入り始める。

詳細年表(選抜)

timeline title OS年表 1945 : ENIAC 1956 : GM-NAA I/O (最初期バッチOS) 1961 : CTSS (MIT) 1964 : Multics開発開始, OS/360 1969 : UNIX (Ken Thompson, Dennis Ritchie) 1973 : UNIXをC言語化 1977 : BSD Unix (UC Berkeley) 1981 : MS-DOS 1.0 1984 : Macintosh System 1.0 1987 : Minix 1.0 1991 : Linux 0.01 1993 : Windows NT 3.1, Debian, Slackware 1995 : Windows 95 2000 : Windows 2000 2001 : Mac OS X 10.0 2005 : Ubuntu 5.04 2007 : iPhone (iOS) 2008 : Android 1.0 2013 : Docker 2014 : Kubernetes 2015 : Windows 10 2020 : Apple Silicon M1 2021 : Windows 11 2023 : Linux 6.0+ Rustサポート 2024 : Android 15, iOS 18, macOS Sequoia 2025 : AI統合の本格化

現代的トレンドと将来展望

Rust in the Kernel

2022年以降、Linux 6.1で初期サポートが入り、段階的に適用範囲が広がっています。

  • 6.1: 基本インフラ
  • 6.2以降: バインディングやサンプル、補助機能の拡張
  • その後: ドライバや周辺サブシステムでの実験的導入が継続

Rustの 所有権・借用チェック が、メモリ安全性の多くのバグ(UAF、buffer overflow)を排除する。GoogleのAndroidチームが主導。

カーネル バイパスI/O

従来のカーネル経由I/Oはオーバーヘッドが問題。解決策:

  • DPDK(Data Plane Development Kit):NICを直接ユーザ空間にマップ
  • SPDK(Storage Performance Development Kit):NVMe直接アクセス
  • VPP(Vector Packet Processing):Cisco系
  • RDMA(Remote Direct Memory Access):InfiniBand、RoCE

Unikernel / MicroVMの復権

FaaS、エッジコンピューティング、WebAssemblyランタイム統合により、極小・高速起動OSが再び注目。

WebAssembly System Interface(WASI)

WASMをブラウザ外で動かすための標準API群。WASI 0.2が2024年に公開され、現在はランタイムごとに対応状況を見ながら使う段階です。ポータブルでサンドボックスしやすく、プラグイン実行基盤や軽量サーバワークロードとの相性が注目されています。

機密計算(Confidential Computing)

  • Intel TDXAMD SEV-SNPARM CCA:VMメモリをハードウェア暗号化
  • Google Cloud Confidential VMAzure Confidential ComputingAWS Nitro Enclaves
  • 金融、ヘルスケア、主権クラウドで需要増

メモリタイプの多様化

  • CXL(Compute Express Link):メモリをネットワーク的にプールし、複数CPUで共有
  • HBM3/HBM4DDR6:帯域爆増
  • Persistent Memory(3D XPoint、終息)NVRAM

AI / LLM統合OS

  • Apple Intelligence:オンデバイス処理とPrivate Cloud Computeを組み合わせる設計
  • Microsoft Copilot+ PCNPUを前提にしたクライアント機能拡張
  • Android AICore / Gemini Nano:オンデバイスモデルの利用拡大
  • GPU/NPUスケジューラLinux DRM、Windows WDDM、macOS Metal周辺でアクセラレータ統合が進む

サステナブルコンピューティング

電力効率、カーボンアウェアスケジューリング、再生可能エネルギーへの移行。

量子コンピューティング対応OS

量子コンピュータの制御システム(IBM Qiskit、Google Cirqなど)はクラシックOS上で動くが、将来的には量子・クラシックハイブリッドのための新たな抽象が必要となる可能性。


実践リファレンス

必須Linuxコマンド

ファイル操作

ls -la                   # 詳細リスト
cp -r src/ dst/          # 再帰コピー
mv old new               # 移動/改名
rm -rf dir/              # 再帰削除(注意)
ln -s target link        # シンボリックリンク
find / -name "*.conf"    # 検索
locate file              # インデックス検索(mlocate)
stat file                # メタデータ
file file                # 種類判定
tree /etc                # ツリー表示

テキスト処理

cat, less, more, head, tail
grep "pattern" file
sed 's/foo/bar/g' file
awk '{print $1, $NF}' file
sort | uniq -c | sort -rn
cut -d: -f1 /etc/passwd
tr 'a-z' 'A-Z'
wc -l file
diff -u f1 f2

プロセス・ジョブ

ps aux                   # 全プロセス
pgrep -f pattern
kill -TERM <pid>
killall <name>
top / htop / btop
jobs, fg, bg, nohup, disown

ネットワーク

ip addr, ip route, ip link
ss -tulpn                # ソケット統計
dig +short example.com
curl -v https://example.com
wget -r -np
ssh user@host -L 8080:localhost:80
rsync -avz src/ user@host:dst/
nc -lvnp 4444            # netcat

パッケージ管理

# Debian/Ubuntu
apt update && apt upgrade
apt install <pkg>
apt search <pattern>

# RedHat/Fedora
dnf install <pkg>
dnf search <pattern>

# Arch
pacman -Syu
pacman -S <pkg>
yay -S <aur-pkg>

# macOS
brew install <pkg>
brew upgrade

# Windows
winget install <id>
choco install <pkg>

システム情報

uname -a
hostnamectl
lscpu, lsmem, lsblk, lspci, lsusb
uptime, w
who, last
dmesg | tail
journalctl -xe
systemctl status <svc>

重要なシステムコール一覧(Linux, x86-64)

番号 名前 説明
0 read ファイルから読む
1 write ファイルに書く
2 open(legacy)/ 257 openat ファイル開く
3 close fd閉じる
9 mmap メモリマップ
10 mprotect 保護変更
11 munmap アンマップ
12 brk ヒープ拡張
13 rt_sigaction シグナルハンドラ設定
22 pipe パイプ作成
32 dup fd複製
39 getpid プロセスID取得
41 socket ソケット作成
42 connect 接続
43 accept 受入
44 sendto UDP送信
45 recvfrom UDP受信
56 clone プロセス/スレッド生成
57 fork プロセス生成
59 execve プログラム実行
60 exit プロセス終了
61 wait4 プロセス待機
62 kill シグナル送信
63 uname システム情報
78 getdents ディレクトリ読む
79 getcwd 現在ディレクトリ
202 futex 高速ユーザ空間mutex
218 set_tid_address TIDアドレス設定
231 exit_group スレッドグループ終了
232 epoll_wait I/Oイベント待ち
233 epoll_ctl epoll制御
257 openat ディレクトリ相対open
262 newfstatat stat
281 epoll_pwait signal mask付きepoll_wait
291 epoll_create1 epoll作成
318 getrandom 暗号論的乱数
425 io_uring_setup io_uring初期化
426 io_uring_enter io_uring実行
427 io_uring_register io_uring登録
435 clone3 拡張clone
437 openat2 拡張openat
439 faccessat2 拡張access

完全なリストは ausyscall --dump/usr/include/asm/unistd64.h/usr/include/asm/unistd_64.h

signal一覧

番号 名前 デフォルト 説明
1 SIGHUP Term ハングアップ、設定再読込に慣例
2 SIGINT Term Ctrl-C
3 SIGQUIT Core Ctrl-\、コアダンプ
4 SIGILL Core 不正命令
5 SIGTRAP Core デバッガ
6 SIGABRT Core abort(3)
7 SIGBUS Core バスエラー
8 SIGFPE Core 浮動小数点例外
9 SIGKILL Term 強制終了(ハンドル不可)
10 SIGUSR1 Term ユーザ1
11 SIGSEGV Core セグフォルト
12 SIGUSR2 Term ユーザ2
13 SIGPIPE Term 閉じたパイプ書込
14 SIGALRM Term alarm(2)
15 SIGTERM Term 終了要求(捕捉可)
17 SIGCHLD Ign プロセス状態変化
18 SIGCONT Cont 再開
19 SIGSTOP Stop 停止(ハンドル不可)
20 SIGTSTP Stop Ctrl-Z
23 SIGURG Ign 帯域外データ
24 SIGXCPU Core CPU時間制限超過
25 SIGXFSZ Core ファイルサイズ制限超過

Linux運用でよく触る確認点

日常運用では、ファイルシステム・プロセス・サービス・ネットワークを別々のコマンドで見ることになる。最初に覚えると効率が上がるものを絞ると次の通り。

systemctl status <service>        # サービス状態
journalctl -u <service> -n 100    # サービスログ
journalctl -k -n 100              # カーネルログ
ss -tulpn                         # 待受ポートとプロセス
lsblk -f                          # ブロックデバイスとFS
df -h                             # 容量
free -h                           # メモリ概観
vmstat 1                          # CPU / run queue / swap
iostat -xz 1                      # ディスク待ち
sar -n DEV 1                      # NICごとの通信量

このセットは「OSが壊れているのか、アプリが壊れているのか、資源が詰まっているのか」を見分けるための最小セットとして使いやすい。アプリケーションの詳細な監視は オブザーバビリティとモニタリング 章、サービス全体の運用設計は サイト信頼性 章とあわせて読むとつながりやすい。


補足

第6章 オペレーティングシステム

ヒント

OSは「アプリとハードウェアの仲介者」です。プロセス・メモリ・ファイル・デバイスという4つの主要機能と、アプリからOSを呼び出すシステムコールの概念を掴みます。

要点

OSは、CPU時間、メモリ、ファイル、デバイスを複数のプログラムで安全に共有するための仕組みです。本章ではブラックボックスに見えるOSの役割を分解して見ます。

この章が実務で役立つ場面

  • プロセス異常終了、OOM、権限エラーの調査
  • ファイルI/OやソケットI/Oの理解
  • コンテナLinux上のアプリの挙動理解

6.1 OSの役割

OSは、アプリケーションとハードウェアの間に立ち、

を行います。

【図11】OSの立ち位置:

flowchart TB A["アプリケーション"] --> B["システムコール"] B --> C["OS"] C --> D["CPU / メモリ / ディスク / NIC"]

6.2プロセスとスレッド

プロセス

独立した実行単位です。通常は独自の仮想メモリ空間を持ちます。実行中の位置を表すプログラムカウンタやスタックポインタ、レジスタ群といった「いまどこを実行しているか」の状態も含めて考えます。

スレッド

同じプロセス内で資源を共有しながら並行に動く実行単位です。複数のスレッドは同じコード領域やヒープを共有できますが、それぞれが自分のレジスタ状態やスタックを持ちます。

【図12】プロセス内のスレッド構造:

flowchart TB A["プロセス"] --> B["スレッド1"] A --> C["スレッド2"] A --> D["共有メモリ・共有資源"]

直感としては、

  • プロセス = ひとつの独立した作業部屋
  • スレッド = その部屋の中で同時に動く作業者

です。部屋が分かれていれば勝手に机の上を触られにくい一方、同じ部屋の作業者どうしは速く連携できる代わりに、ぶつかりやすくもなります。

6.3システムコール

アプリケーションは、OSの機能を直接たたくのではなく、システムコールを通じて使います。

例:

  • open
  • read
  • write
  • fork
  • exec

fork は現在のプロセスを複製して子プロセスを作る操作です。Linuxではcopy-on-writeが使われるので、「最初から全部のメモリを丸ごとコピーする」と理解すると少しずれます。まずは同じ内容を共有し、書き込みが起きたところから実体化していきます。

exec は「いまのプロセスの中身を別のプログラムに入れ替える」操作です。新しいプログラムでスタックやヒープも初期化されます。Unix系でよく見る forkexec という流れは、

  1. まず子プロセスを作る
  2. その子を別プログラムへ置き換える

という二段階です。

【図13】forkとexecの流れ:

flowchart LR A["親プロセス"] --> B["fork"] B --> C["子プロセス作成"] C --> D["exec"] D --> E["別プログラムとして実行開始"]

6.3.1ファイル記述子という共通の窓口

Unix系OSでは、ファイル、パイプ、ソケットなど多くの資源が「ファイル記述子」という共通の窓口で扱われます。read() は「ファイルから読む関数」というより、ファイル記述子から読む関数 です。

この見方を持つと、

  • ファイルI/O
  • パイプ通信
  • ソケット通信

が、OSから見るとかなり似た形で扱える理由が見えてきます。

6.3.2 mmap はなぜ大事か

mmap はファイルやデバイスをメモリ空間へ写像する仕組みです。これにより、アプリケーションは「読むAPIを何度も呼ぶ」代わりに、「メモリを読むように」ファイル内容へアクセスできます。

直感としては、

  • read = データをコピーして受け取る
  • mmap = その内容がある領域を自分のアドレス空間へつなぐ

という違いです。

【図14】mmapの概念:

flowchart LR A["ファイル"] --> B["mmap"] B --> C["仮想メモリ空間に写像"] C --> D["通常のメモリアクセスのように読む"]

6.4スケジューリング

OSは「いまどの実行主体にCPUを使わせるか」を決めます。

考えるべき観点:

  • 公平性
  • 応答性
  • 優先度
  • リアルタイム性

6.4.1スケジューリングを日常の比喩で見る

スケジューリングは、1台のコピー機を複数人で使う状況に似ています。

  • 1人が長く占有しすぎると不公平
  • 短い作業は早く終わらせたほうが体感がよい
  • 締切のある仕事は優先したい

このバランスを取るのがOSです。

サーバOS、デスクトップOS、リアルタイムOSで重点が違うのも自然です。サーバではthroughput、デスクトップでは応答性、リアルタイムでは期限遵守がより重要になります。

6.5コンテキストスイッチ

CPUがある実行主体から別の実行主体へ切り替わるとき、状態保存と復元が必要です。これがオーバーヘッドになります。

【図15】コンテキストスイッチの流れ:

flowchart LR A["実行中のスレッドA"] --> B["状態保存"] B --> C["次のスレッド選択"] C --> D["状態復元"] D --> E["スレッドB実行"]

6.6仮想メモリ

プロセスに「連続して広いメモリ空間があるように見せる」仕組みです。実際にはページ単位で管理されます。

仮想メモリの利点:

  • プロセス隔離
  • 保護
  • 見通しのよいアドレス空間
  • ディスクとの連携による大きな見かけの空間

OSの観点では、仮想メモリは単なる「ごまかし」ではありません。物理メモリの複雑さを隠しつつ、必要なページだけを主記憶に置くdemand pagingと、プロセス間の保護や共有を両立するための中心的な仕組みです。

【図15-2】仮想アドレスから物理メモリまで:

flowchart LR A["プロセスの仮想アドレス"] --> B["ページテーブル参照"] B --> C["物理メモリ上のページ"] B --> D["未配置ならページフォルト"] D --> C

6.7ページとページフォルト

メモリはページという小さな単位で管理されます。必要なページがまだ物理メモリへ載っていないと、ページフォルトが起きてOSが対応します。

【図16】ページフォルトの処理フロー:

flowchart LR A["仮想アドレスへアクセス"] --> B["ページテーブル確認"] B --> C["物理ページあり"] B --> D["物理ページなし"] D --> E["ページフォルト"] E --> F["OSがページを用意"]

ページフォルトという名前は少し怖く見えますが、実際には「必要になったので今読み込む」という正常系の動作も多いです。異常になるのは、アクセス権がない場所を読もうとした、存在しない領域を触った、などのケースです。

6.8ファイルシステム

ファイルシステムは、ストレージ上のデータを

  • ファイル
  • ディレクトリ
  • パス
  • 権限

として扱えるようにします。

6.8.1永続化とジャーナリング

ファイルシステムで難しいのは、「途中で電源が落ちても壊れにくくすること」です。

そこで使われる考え方の1つが ジャーナリング です。これは、いきなり本体を書き換える前に、

  1. これから何を変えるかを書き残す
  2. 本体を更新する
  3. 完了したら記録を確定する

という順で進める方法です。

これにより、クラッシュ後にも「どこまで終わったか」を追いやすくなります。データベースのログやトランザクションとも発想が似ています。

6.8.2同期I/Oと非同期I/O

I/Oの扱い方には、大きく

  • 同期I/O: 終わるまで呼び出し側が待つ
  • 非同期I/O: 依頼だけ出して、完了はあとで受け取る

という違いがあります。

これはレストランで、

  • 同期 = 自分で厨房の前に立って待つ
  • 非同期 = 呼び出しベルを受け取って、終わるまで別のことをする

ような違いです。

高負荷サーバやGUIアプリで非同期I/Oが重要なのは、CPUを遊ばせにくくできるからです。ただし、コードの流れは少し複雑になります。

6.9なぜOSが大事か

高級言語で書いたコードも、最終的には

OSに深く依存します。

6.10ミニ比較表

概念 何をしているか 混同しやすいもの 違い
プロセス 独立した実行単位 スレッド 通常はメモリ空間を分ける
スレッド 共有しながら並行実行 プロセス 共有資源が多い
仮想メモリ 見かけのアドレス空間 物理メモリ 実在のRAMとは別
システムコール OSへの入口 ライブラリ関数 ライブラリの裏でOSを呼ぶこともある

6.11よくある誤解

よくある誤解

スレッドは「軽いプロセス」ですが、軽いから簡単というわけではありません。共有メモリゆえに競合やデッドロックの問題が増えます。

6.12例題

【図17】OSに関する問題の切り分け:

flowchart LR A["問題を見る"] --> B["CPU / メモリ / ファイル / プロセスのどれか判定"] B --> C["OSの責務に対応づける"] C --> D["適切な概念で説明する"]

例題1: read() がライブラリ関数ではなくOSの機能にも関係するのはなぜか。

解説: 実際のファイルやデバイスアクセスはOSが管理しているからです。

例題2: プロセススレッドの最も大きな違いを一文で述べよ。

解説: 通常、プロセスは独立したメモリ空間を持ち、スレッドは同じプロセス内でそれを共有します。

例題3: ページフォルトは必ず異常終了を意味するか。

解説: 意味しません。必要なページを読み込む正常なページフォルトもあります。

6.15ユースケース

Webサーバ

コンテナ

  • 名前空間やcgroupsによって資源を分離
  • OSの仕組みの上に乗っている

まとめ

オペレーティングシステムは、資源管理、抽象化、分離を担う土台です。プロセス、メモリ、ファイル、I/O、仮想化までをまとめて見ると、アプリケーションの下で何が起きているかが立体的に見えてきます。

参考文献

公式・標準

論文

講義・記事

書籍

解説・補助