OS
概要
初心者から大学院レベルまでの包括的解説
現代のコンピュータシステムは、アプリケーションからクラウドインフラ、モバイル端末、IoT までのすべてが OS の上に成り立っています。この章では、OS の理論・実装・歴史・最新動向を体系的に整理します。
この章の対象
この章は次の読者を想定しています。
- 初心者向け: OS の基本概念から学びたい方
- 開発者向け: システムプログラミング・パフォーマンス改善に取り組む方
- インフラ/SRE 向け: Linux カーネル・コンテナ・クラウドを深く理解したい方
- 研究者・学生向け: OS 設計の理論的基盤を押さえたい方
OSとは何か
オペレーティングシステム(Operating System, OS) は、コンピュータのハードウェアとソフトウェアの資源を管理し、プログラムが実行するための共通サービスを提供するシステムソフトウェアである。OSの本質は以下の三つの側面に凝縮される。
- リソース管理者(Resource Manager) — CPU、メモリ、ディスク、ネットワーク、周辺機器を公平かつ効率的に配分する。
- ハードウェア抽象化層(Hardware Abstraction Layer) — 多様なハードウェアの違いを隠蔽し、統一的なインターフェースを提供する。
- 仮想マシン提供者(Virtual Machine Provider) — 各プロセスに「自分専用のコンピュータ」という幻想を与え、保護・分離を実現する。
キーコンセプト: OSは「ユーザーと機械の仲介者」であり、同時に「ハードウェアの複雑性を隠蔽するレイヤー」であり、さらに「各プロセスに独立した仮想世界を提供するハイパーバイザ的存在」でもある。これら三つの役割を統合的に担う点が、OSを他のソフトウェアから際立たせる。
現代のOSは単なる「PCを動かす土台」にとどまらず、クラウド、コンテナ、モバイル、組み込み、リアルタイム制御、さらにはAI推論基盤に至るまで、情報社会の根幹を支える巨大な技術スタックである。Linux カーネルも、数千万行規模のコードと多数の開発者による長年の分散開発の上に成り立つ、世界最大級のオープンソース基盤の一つである。
目次
- OSの定義と哲学
- OSの主要機能
- OSのアーキテクチャ
- カーネルモードとユーザーモード
- システムコールとABI
- Linuxアーキテクチャの詳細
- コアコンポーネント
- ブートプロセスと初期化
- プロセス管理
- スレッドと並行性
- CPUスケジューリング詳細
- 同期機構とプロセス間通信
- デッドロック・飢餓・レースコンディション
- メモリ管理
- ファイルシステムとI/O
- ストレージ管理とRAID
- デバイス管理とドライバ
- ネットワーキング
- セキュリティ
- 仮想化
- コンテナ技術
- デスクトップOSの詳細比較
- モバイルOS
- リアルタイムOSと組み込みOS
- 分散OS・クラウドOS
- OSのパフォーマンス分析とチューニング
- OSの歴史
- 現代的トレンドと将来展望
- 実践リファレンス
- 参考資料
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 はこれらを抽象化し、プログラマが扱いやすい「仮想計算機」を提供する。 というシステムコールは、内部的にはセクタ計算、キャッシュ参照、DMA設定、割り込み待機を経て実行されるが、プログラマからは単なる関数呼び出しに見える。
- リソース管理者としてのOS:複数の競合するプロセスが CPU、メモリ、I/O を共有する際、公平性・効率・保護を担保するのが OS の責務である。
三位一体の役割
OSの設計哲学
UNIX哲学は現代OSの根幹を形作っている:
- Do one thing and do it well — ツールは一つのことを上手にやる。
- Write programs to work together — プログラムは協働できるよう設計する(パイプ)。
- Handle text streams as universal interface — テキストストリームをユニバーサルなインターフェースとする。
- Everything is a file — すべてはファイルである(デバイス、ソケット、プロセス情報まで)。
この哲学は Linux、macOS (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の主要機能
1. プロセス管理(Process Management)
OS はプロセスの生成・終了・状態遷移・スケジューリング・プロセス間通信を管理する。Linux では fork()、exec()、wait()、exit() という古典的な UNIX API に加え、clone()、、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 網の上にトンネルとして重ねる仕組みである。Linux の Netfilter はカーネル内パケットフィルタ基盤で、iptables や nftables はその上でルールを定義するための仕組みである。
6. セキュリティと保護
認証(PAM, Kerberos)、認可(DAC, MAC, RBAC, ABAC)、監査(auditd, ETW)、暗号化(dm-crypt, BitLocker, FileVault, APFS encryption)、サンドボックス(seccomp, AppArmor, SELinux, Windows AppContainer)。認可方式のうち DAC は所有者が権限を決める方式、MAC は OS 側の強制ルールで制御する方式、RBAC は役割ベース、ABAC は属性ベースの制御である。
7. ユーザーインターフェース
CLI(bash, zsh, fish, PowerShell, cmd)、GUI(X11, Wayland, Quartz Compositor, Windows DWM)、API(POSIX, Win32, Cocoa/UIKit)という三層のインターフェースを提供する。たとえば Wayland は Linux 系の新しい表示プロトコル、Quartz Compositor は macOS の画面合成基盤、DWM は Windows の 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のアーキテクチャ
OS カーネルの設計は歴史上、複数の異なる哲学のもとで発展してきました。性能・信頼性・保守性・セキュリティのトレードオフが異なります。
1. モノリシックカーネル(Monolithic Kernel)
すべてのOSサービス(メモリ管理、プロセス管理、ファイルシステム、デバイスドライバ、ネットワーク)が単一のアドレス空間で特権モード実行される。
【図1】モノリシックカーネルの構造:
長所:
- 関数呼び出しで全機能にアクセス可能 → 極めて高速
- キャッシュ効率が良い
- 実装が単純明快(大まかには)
短所:
- 一つのバグ(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 でつながる、という分離のしかたを見る。
長所:
- 信頼性:一つのサーバが落ちても他は生存し、再起動で復旧可
- セキュリティ:特権コードが小さく監査しやすい(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・メッセージパッシングをカーネル内部構造として持ちつつ、性能のためファイルシステムやネットワークもカーネル空間に取り込む。
代表例:
- Windows NT(Windows 2000/XP/Vista/7/8/10/11 の基盤)— NT カーネル + Executive + サブシステム
- macOS / iOS / iPadOS / watchOS / tvOS(XNU = “X is Not Unix”)— Mach + BSD + I/O Kit
- BeOS / Haiku
- ReactOS(Windows NT 互換のオープンソース)
【図3】XNU の内部構造:
この図では、macOS / iOS の XNU が Mach、BSD、I/O Kit を重ね合わせたハイブリッド構造になっている点を見る。
【図4】Windows NT の内部構造:
この図では、Windows がユーザモードのサブシステムと Executive 群、さらに HAL を分けている点に注目すると把握しやすい。
4. 層型カーネル(Layered Kernel)
Dijkstra の THE OS (1968) が提唱した設計。各層が下位層のみを呼び出し、逆方向の依存を禁止する。
【図5】層型カーネル(THE OS):
教育的価値は高いが、層の厳密な区切りが実装と性能を犠牲にするため、純粋な層型OSは現代では稀。ただし Multics や OS/2 は層型の影響を強く受けた。
5. エクソカーネル(Exokernel)
MIT の Frans Kaashoek らが 1990年代に提唱。「カーネルは抽象化を提供せず、物理リソースへの保護された直接アクセスのみを提供する」という極端な設計哲学。ファイルシステムやネットワークプロトコルはユーザライブラリ(libOS)として実装される。
意図: アプリケーションが自分に最適な抽象を選べるようにする。DB サーバは専用ファイルシステム libOS を使い、Web サーバは独自 TCP スタックを使える。
代表例: MIT Exokernel(XOK, Aegis, ExOS)、Nemesis(Cambridge)。商用成功には至らなかったが、Unikernel や User-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 モード。
特権レベルの意味
ユーザモードで禁止される代表的な命令(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):Linux で
gettimeofday()、、getcpu()などの頻繁に呼ばれる関数をユーザ空間にマップし、カーネルに遷移せず実行する。 - io_uring:システムコール境界を跨がない共有リングバッファでI/Oを発行・完了通知する。
- eBPF:小さなサンドボックスプログラムをカーネル内で実行し、ユーザ空間に戻る頻度を減らす。
- ユーザ空間ドライバ(DPDK, SPDK):NIC や NVMe を直接ユーザ空間にマップし、カーネルを通さずパケット・I/Oを処理する。
システムコールとABI
システムコール(syscall)は、ユーザプログラムがカーネルに処理を依頼するための公式インターフェースである。
Linux x86-64 の syscall 規約
x86-64 では、Linux は syscall 命令を使う新しい規約を採用している:
| レジスタ | 用途 |
|---|---|
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 のシステムコール一覧は や man 2 syscalls で確認できる。
POSIX とABI
**POSIX(Portable Operating System Interface)**は IEEE が制定するUnix系OSの標準API。POSIX.1 は基本API(fork, exec, open, read, write)を、POSIX.1b はリアルタイム拡張(, )を、POSIX.1c は pthread をカバーする。
ABI(Application Binary Interface) は ISA・OSごとに異なり、関数呼び出し規約・システムコール規約・構造体レイアウト・実行ファイル形式(ELF, Mach-O, PE)を定める。同じOSでも ABI が異なれば実行できない(Linux x86-64 と Linux ARM64 は互換性なし)。
高速呼び出し機構の進化
int 0x80(i386 時代)— ソフトウェア割り込み。遅い。SYSENTER/SYSEXIT(Pentium II、Intel)— 専用命令で高速化。SYSCALL/SYSRET(AMD64、Intel 64)— 現代のx86-64で標準。- vDSO(上述)— 一部システムコールをユーザ空間で完結。
- 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システムの階層構造:
主要サブシステム
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 博士らによって実装され、リクエスト遅延の予測可能性を向上させる。
リアルタイムプロセスは 、、 の各ポリシーで別系統にスケジュールされる。
2. メモリ管理 (mm/)
- バディアロケータ:物理ページを2の冪乗サイズで管理。
- スラブアロケータ(SLAB/SLUB/SLOB):小さなオブジェクトを効率的に管理。Linux では SLUB が標準。
- デマンドページング、スワップ、ページキャッシュ、Transparent Huge Pages(THP)、NUMA policy、memcg (cgroup memory controller)。
- mmap、brk/sbrk、mremap、madvise。
3. 仮想ファイルシステム (VFS, fs/)
Sun Microsystems が1985年に NFS のため導入した設計を Linus が採用。struct inode、struct dentry、struct file、 が抽象化の核となる。これにより 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)
フック型のセキュリティ拡張機構。SELinux、AppArmor、TOMOYO、Yama、Landlock、SMACK などの「スタック可能な」セキュリティモジュールを挿入できる。
Linux ディストリビューション
Linux カーネル単体では OS として動かない。シェル、ユーティリティ、パッケージマネージャ、デスクトップ環境などを組み合わせた ディストリビューション が「ユーザが使うLinux」である。
【図7】主要 Linux ディストリビューション系統図:
コアコンポーネント
カーネル(Kernel)
OSの中核。ハードウェアに直接触れる最も特権的なソフトウェア。カーネルが提供する主要サービスは以下に集約される。
シェル(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, など)、文字列操作、数学関数、ロケール、DNS レゾルバ、ダイナミックローダ(ld-linux.so)を含む。
主要な派生/代替:
- musl libc:軽量・簡潔、Alpine Linux で採用。
- uClibc / uClibc-ng:組み込み向け。
- Bionic:Android 用 libc(glibc ではなく、BSD ベース)。
- Newlib:RTOS 向け。
- ucrt (Universal CRT):Windows 10 以降の CRT。
C++ 標準ライブラリ
libstdc++(GNU)、libc++(LLVM)、Microsoft STL。C++20/23 の 、、、 などを提供。
その他重要ライブラリ
libssl/libcrypto(OpenSSL、LibreSSL、BoringSSL)libcurl、libnghttp2zlib、liblzma、libzstd(圧縮)libX11、libwayland-client(GUI)systemdクライアントライブラリ(libsystemd)
システムユーティリティとデーモン
Linux の典型的な常駐プロセス:
macOS では launchd(PID 1)がこれらをすべて統合している。Windows では services.exe がサービスマネージャを担う。
ブートプロセスと初期化
電源ボタンを押してからログインプロンプトが現れるまで、OS は複雑な一連の初期化を行う。
UEFI ブートの流れ(現代的 x86-64 PC)
この図では、「ファームウェア → ブートローダ → カーネル → init/systemd」という主な責務の受け渡しを見る。
詳細フェーズ
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-64、RISC-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: カーネルのロードと初期化
- 展開:
vmlinuzは通常 gzip/xz/zstd 圧縮されたbzImageで、先頭の decompressor が自身を展開する。 - アーキテクチャ初期化: → へ。
- メモリマップ取得:e820 テーブル(BIOS)または EFI memory map から物理メモリを把握。
- ページテーブルセットアップ:Identity mapping → カーネル仮想アドレス空間構築。
- (
init/main.c):各サブシステム初期化 — スケジューラ、割り込み、RCU、タイマ、コンソール、rest_init()、kernel_init スレッド起動。 - initramfs:一時ルートファイルシステム。ドライバをロードし、真のルートを見つけてマウント。
initプロセスの起動:PID 1 として/sbin/init(systemd、OpenRC、SysV init)を exec。
Phase 4: ユーザ空間初期化(systemd)
systemd は依存関係グラフで並列にサービスを起動する。主な単位:
.service— サービス(デーモン).target— グループ化(ランレベル相当:graphical.target、multi-user.target、rescue.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
プロセス管理
プロセスとは
プロセス は実行中のプログラムの動的実体であり、以下を保持する:
- アドレス空間:テキスト(コード)、データ、BSS、ヒープ、スタック、メモリマップ領域
- 実行コンテキスト:レジスタ(PC、SP、汎用、浮動小数点、SIMD)、モード情報
- リソース:オープンファイル(ファイルディスクリプタ)、ソケット、シグナルマスク
- プロパティ:PID、PPID、UID/GID、優先度、CPU 時間、作業ディレクトリ、環境変数
- 状態:実行中、実行可能、ブロック中、停止中、ゾンビ
Linux のプロセス構造体
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 所属
// ... 数百のフィールド
};
プロセス状態遷移
この図では、プロセスが「実行可能」「実行中」「待ち」「停止」「ゾンビ」をどう行き来するかを流れで押さえる。
Linux の状態コード(ps の STAT 列):
R— Running (実行中 or 実行可能)S— Sleeping (割り込み可能)D— Uninterruptible sleep (通常ディスクI/O、kill できない)T— Stopped (SIGSTOP 後)t— Tracing stop (デバッガ)Z— Zombie (終了したが親が 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() はアドレス空間全体をコピーするため高コスト。現代OSは Copy-on-Write でこれを最適化する:
fork()時、親子ともにページテーブルは同じ物理ページを指す。- ただしエントリは読み取り専用にマーク。
- どちらかが書き込もうとするとページフォルト(#PF, write protect violation)発生。
- カーネルが当該ページのコピーを作り、書き込んだプロセスのページテーブルを新ページにリダイレクト。
- 読み取りのみのページは永遠に共有(典型的には共有ライブラリやテキスト領域)。
多くの fork() の後にすぐ exec() が呼ばれるケースでは、COW により実際のコピーはほとんど発生しない。
プロセス階層と init
Unix では全プロセスが唯一の祖先 PID 1(init/systemd)に辿り着く木構造を成す。親プロセスが子より先に終了した場合、孤児(orphan)プロセスは init に再親子付けされ、ゾンビ回収は init の責任となる。
Windows のプロセスモデル
Windows のプロセスは以下の点で Unix と異なる:
fork()がない:CreateProcess()は一度に新プログラムを起動する。- プロセス作成が高コスト:スレッド作成の方が推奨される(Windows での軽量並行処理の伝統)。
- Job Object:プロセスグループを包括的に管理。cgroup 的役割。
- プロセスのハンドル:オブジェクトマネージャで管理、参照カウント。
スレッドと並行性
スレッドとは
スレッド は同一プロセスのアドレス空間を共有する実行の流れ。プロセスが「家」なら、スレッドは「その中で同時に活動する人々」。
| 特性 | プロセス | スレッド |
|---|---|---|
| アドレス空間 | 独立 | 共有 |
| ファイルディスクリプタ | 独立 | 共有 |
| スタック | 一つ | 各スレッド固有 |
| レジスタ | 一つ | 各スレッド固有 |
| シグナルマスク | 共有 | 各スレッド固有 |
| 生成コスト | 高(数ms〜数十ms) | 低(数μs〜数百μs) |
| コンテキストスイッチ | 重い(アドレス空間切替あり) | 軽い |
| 通信 | IPC(パイプ、ソケット、共有メモリ) | 直接メモリアクセス |
| 安全性 | 独立で頑健 | 共有ゆえ競合リスク |
カーネルスレッド vs ユーザスレッド
- カーネルスレッド(1:1 モデル):OS が各スレッドをスケジュール。真の並列性を活用可能。Linux
pthread、Windows 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 は以下を提供:
- , , ,
- , , , ,
- (スレッドローカルストレージ)
- (CPU アフィニティ)
- ,
Linux におけるスレッド実装の歴史
- LinuxThreads(1996〜):各スレッドが別 PID、シグナル扱いに難あり。
- NGPT (Next Generation POSIX Threads):IBMの試み、失敗。
- NPTL (Native POSIX Thread Library, 2003〜):1:1 モデル、
clone()+ futex 活用。現行標準。
NPTL では で軽量スレッドを生成。
並行性 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++11 は 、acquire、release、relaxed、consume を提供。プログラマが原子操作に明示的にメモリ順序を指定する。
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 でカーネルに待機をキューイング。
glibc の 、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 バースト長は事前に分からず推定が必要。指数移動平均で過去バーストから予測する:
ここで は直近バースト実測、 は推定値、。
3. ラウンドロビン(RR)
各プロセスに固定タイムクォンタム q を与え、使い切ったらキュー末尾に戻す。q が小さすぎると切替オーバーヘッド、大きすぎると応答性悪化。典型的 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 による設計。赤黒木()で 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 は「今この時点で実行候補にしてよい」という意味で、レイテンシ要求( で 指定)を尊重しやすい。
リアルタイムクラス
- :優先度内 FIFO、自発的 yield まで実行。リアルタイム。
- :FIFO にタイムスライス追加。
- :EDF + CBS(Constant Bandwidth Server)で (runtime, deadline, period) を指定。Hard RT タスクに適する。
- (=SCHED_NORMAL):CFS/EEVDF で管理。
- :CPUバウンドでレイテンシ不要。
- :最低優先度、他が何もないとき。
マルチコア・スケーラビリティ
現代の Linux はコアごとに per-CPU ランキュー を持ち、互いに独立にスケジュールする。ランキュー は「その CPU で実行待ちしているタスクの待ち行列」のことで、負荷分散(load balancing) はペリオディックに動き、アンバランスを検知したら タスクマイグレーション で再配置する。
関連概念:
- CPU affinity(,
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: , , 。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 の美しい発明。無名パイプ と名前付きパイプ 。単方向、バッファリング、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 共有メモリ: +
mmap - SystemV 共有メモリ:
shmget+shmat(レガシー) - memfd_create / memfd_secret(Linux)
- ハイブリッドアプローチ:io_uring の SQE/CQE リングバッファも共有メモリ
4. メッセージキュー
- POSIX mqueue:, ,
- SystemV msg:
msgget,msgsnd,msgrcv
5. ソケット
- UNIXドメインソケット:同一マシン上の IPC、高速
- TCP/UDP ソケット:ネットワーク越し
- Netlink ソケット:Linux カーネル↔ユーザ空間
6. D-Bus
Linux デスクトップ(GNOME/KDE)および systemd で使われる高水準 IPC。オブジェクト、メソッド、シグナル、プロパティの概念を提供。gdbus、busctl、dbus-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】デッドロックの循環待ち:
Coffman 条件
デッドロックが起こるには次の4つが同時成立する必要がある:
- Mutual Exclusion(相互排除):リソースは一度に一つのプロセスしか保有できない。
- Hold and Wait(保有と待機):既にリソースを保有しつつ、別のリソースを待つ。
- No Preemption(非奪取):リソースを強制的に取り上げることはできない。
- Circular Wait(循環待ち):プロセス間で循環的な待ち関係がある。
デッドロック対策
予防(Prevention):4条件のいずれかを崩す
- 相互排除を崩す:リソースを共有可能にする(常に可能とは限らない)
- 保有と待機を崩す:全リソースを最初に一括取得()
- 非奪取を崩す:待機時に保有リソースを解放、再取得時にやり直し
- 循環待ちを崩す:リソースに全順序を定義し、番号の昇順でしか取得しない → Linux カーネルの
lockdepが自動検証
回避(Avoidance):実行時チェック
- Banker’s Algorithm(Dijkstra, 1965):リソース要求時、安全状態が保てるかシミュレート。安全状態 = 全プロセスが満足する実行順序が存在する状態。要求プロセス数・リソース種類・数すべて事前判明が前提で、汎用 OS では使いにくい。
検出と回復(Detection & Recovery):定期的にリソース要求グラフを走査し、サイクルを検出したら回復措置
- プロセスの強制終了
- ロールバック(DB は普遍的にこれを行う)
- 資源の強制解放
無視(Ostrich Algorithm):多くの汎用OS(Linux, Windows)は「起きたら困るけど滅多にないから対処しない」方針。Tanenbaum はこれを「ダチョウ法」と命名。
Linux の lockdep
Linux カーネルは でコンパイルすると、実行時にすべてのロック取得順序を記録し、潜在的デッドロックパターン(循環)を検出して警告する。これにより広範なカーネルロックのバグが発見された。
飢餓(Starvation)
優先度の低いタスクが、高優先タスクに常に追い抜かれて永遠に実行されない状態。エイジング(aging) = 待機時間に応じて優先度を動的に上げる、で緩和。
優先度逆転(Priority Inversion)
低優先プロセスが持つロックを高優先プロセスが待つ間、中優先プロセスが割り込んで CPU を奪う現象。
歴史的事件:火星探査機 Mars Pathfinder(1997) でこれが発生し、タイムアウトによるシステムリセットが多発した。VxWorks の priority inheritance protocol を有効にして解決。
対策:
- Priority Inheritance:ロック保有者を一時的に最高待機者の優先度まで引き上げ。
- Priority Ceiling:各ロックに最高優先度を割り当て、取得者はそれに昇格。
POSIX では で指定可能。
レースコンディション(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);
}
対策:、ハンドルベース API、capabilities。
メモリ管理
現代 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-64 は 48bit = 256TB、最新 LA57 で 57bit = 128PB)を提供。MMU が仮想→物理変換を行う。
利点:
- プロセス間分離(互いのメモリを破壊できない)
- 物理メモリより大きな仮想空間(スワップ、オーバーコミット)
- 連続的なアドレス空間(断片化された物理メモリを統合)
- 共有メモリ(同一物理ページを複数プロセスにマップ)
- COW、デマンドページング、メモリマップトファイル
ページング
仮想アドレス空間を固定サイズ(典型的に 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-64 の TLB は典型的に L1 dTLB が 64 エントリ、L2 STLB が 1024〜2048 エントリ。
TLB シュートダウン:あるコアがページテーブルを更新したとき、他コアの TLB も無効化する IPI(Inter-Processor Interrupt)が必要。マルチコアでは意外に高コスト。
Huge Pages(大ページ)
通常 4KB の代わりに 2MB や 1GB のページを使うと、TLB エントリで大きな領域をカバーでき、ミスが減る。
- Linux の THP(Transparent Huge Pages):自動で昇格
- 明示的 hugetlbfs: で予約
- Windows Large Pages:
データベース(PostgreSQL の 、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 エンジン |
Linux は 2 Q (active/inactive list) + WorkingSet refault + reclaim で実装。
Working Set と スラッシング
Working Set:時刻 t から過去 時間にアクセスされたページ集合 。
スラッシング:物理メモリが全プロセスの working set 総和より小さく、ページフォルトとディスクI/Oが頻発して CPU がほぼ idle になる状態。
対策:
- メモリ追加
- プロセスをスワップアウト(サスペンド)
swappinessパラメータ調整- OOM killer(Linux の最後の手段)
メモリアロケータ
物理メモリ層:バディアロケータ
ページを 2^n ページの塊(order-n block)で管理。要求時は最小の十分な塊を取り、必要なら分割。解放時は buddy(兄弟)が free なら統合。
- 外部断片化を大幅に削減
- 最大 order は CONFIG_FORCE_MAX_ZONEORDER(通常 10、4MB 塊まで)
cat /proc/buddyinfoで確認可能
スラブアロケータ(SLAB / SLUB / SLOB)
同サイズのオブジェクト(, inode, dentry, 等)を効率管理。kmalloc / の基盤。
- 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 (遅)
Linux の NUMA 対応:
numactlコマンド、libnuma- カーネルパラメータ:
- mempolicy:, ,
numastat、numactl --hardware- Transparent NUMA balancing (auto-migrate pages)
Copy-on-Write、Zero-Fill、Demand-Zero
- Zero-fill on demand: した領域は全て を指す。書き込み時に初めて実メモリ割り当て。
- COW:
fork後の書き込みで初めてコピー。 - 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
ファイルとディレクトリ
ファイル:名前のついたバイトシーケンスに属性(所有者、権限、タイムスタンプ)を付けたもの。
ディレクトリ:ファイル名→inode の対応表。ディレクトリ自体もファイルの一種(type=directory)。
Unix のファイル階層(FHS)
FHS(Filesystem Hierarchy Standard) は、Unix/Linux 系で「どの種類のファイルをどこに置くか」をそろえるための慣習・標準である。
inode
Unix ファイルシステムの中核データ構造。各ファイルに一意の inode 番号があり、メタデータとデータブロック位置を保持する。名前そのものはディレクトリ側にあり、inode は「その実体情報」を持つ。
【図20】inode の構造:
この図では、ファイル名そのものは inode に入らず、inode 側には属性とデータ位置が入る、という役割分担を見る。
ハードリンク:複数のディレクトリエントリが同じ inode を指す(ln src dst)。
シンボリックリンク:パス名を格納した特殊ファイル(ln -s src dst)。
stat コマンドで詳細確認、ls -i で inode 番号表示。
ext4 / XFS / Btrfs / ZFS / APFS / NTFS の比較
ここで ジャーナリング は「更新前後の記録を先に残して、障害時に整合性を戻しやすくする仕組み」、CoW(Copy-on-Write) は「上書きせず新しい場所へ書いてから差し替える方式」、VSS は Windows の 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 -h の buff/cache 列がこれ。
Write-back cache:write() で RAM に書き、後で flushd/pdflush/bdi-flush がディスクに書く。sync/fsync/fdatasync/msync で強制フラッシュ。
Direct I/O():ページキャッシュを迂回してディスクに直接 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 AIO:Linux 実装は貧弱でほとんど使われない
- 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 発行可
- ファイル、ソケット、タイマ、
fsync、accept、send/recvなど幅広くサポート - で依存チェーンを形成
メモリマップトファイル(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):プロセスごとの情報()、カーネル情報
- 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-provisioning、SLC 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 から見えない
- ソフトウェア RAID:Linux の
md、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 相互運用
- Lustre:HPC、数千ノード
- 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 ドライバモデル階層:
カーネルモジュール
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 ネットワーク階層:
ソケット 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):帯域制御、シェーピング、ポリシング。
- Conntrack:NAT、接続追跡。
- 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 プログラムをカーネル内で実行する革新的機構。
主な用途:
- パケットフィルタリング:cgroup eBPF, tc eBPF
- XDP(eXpress Data Path):NIC ドライバ直下で実行、低遅延ルータ・ファイアウォール
- トレーシング:kprobe, uprobe, tracepoint (bpftrace, bcc)
- セキュリティ:Seccomp BPF、Cilium(Kubernetes ネットワークセキュリティ)、Falco
- 可観測性:Pixie、Parca、Pyroscope
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;
}
名前空間とネットワーク分離
Linux の network namespace により、プロセス群ごとに独立した NIC、ルーティングテーブル、iptables を持てる。Docker、Kubernetes、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)が原則です。単一の防壁に依存せず、複数の独立した層で攻撃者を遅延・検出します。
基本的脅威モデル
- 不正アクセス:許可されない読み書き・実行
- 権限昇格:一般ユーザから root への昇格、サンドボックス脱出
- 機密性破壊:データの盗難、パスワード漏洩
- 完全性破壊:データ・コード改ざん、rootkit
- 可用性破壊:DoS、クラッシュ、資源枯渇
- 否認:操作の否認(監査ログで防御)
アクセス制御モデル
DAC(Discretionary Access Control)
Unix の rwx パーミッションが典型。所有者がアクセス権を自由に設定できる。
拡張: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、Docker、systemd、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: (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-strong、Windows の /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 → Kernel。Linux では 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 シリーズ内蔵
仮想化
仮想化の種類
Type-1 ハイパーバイザ(Bare Metal)
ハードウェア直上で動作。OS なしで動く。
- VMware ESXi:エンタープライズデファクト
- Microsoft Hyper-V:Windows Server 統合、Azure 基盤
- Xen:AWS EC2 初期、現在は Nitro に移行、NetBSD 由来
- KVM(Kernel-based Virtual Machine):Linux カーネルに統合、Type-1 相当
- Proxmox VE、oVirt、OpenStack(管理基盤)
Type-2 ハイパーバイザ(Hosted)
ホスト OS 上で動作。
- VMware Workstation / Fusion
- Oracle VirtualBox
- Parallels Desktop(Mac)
- QEMU(ユーザモード)
- UTM(QEMU フロントエンド、macOS)
仮想化技術の分類
完全仮想化(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 仮想化スタック:
メモリ仮想化
- シャドウページテーブル: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.framework、Microsoft Hypervisor Platform
コンテナ技術
コンテナとは
プロセス単位の軽量仮想化。完全なゲスト 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】コンテナランタイムの階層:
Docker
2013 年、Solomon Hykes らが dotCloud で開発。コンテナを「クラウド時代のデプロイメント単位」として普及させた。
主要機能:
- Dockerfile:イメージビルドレシピ
- Image layers:差分ベース、共有
- Docker Hub:パブリックレジストリ
- Docker Compose:複数コンテナのオーケストレーション
- Docker Swarm:クラスタリング(Kubernetes に市場で敗北)
Kubernetes
Google の内部システム Borg/Omega に触発され、2014 年に発表。現在 CNCF が保守する事実上のクラウドオーケストレータ標準。
【図16】Kubernetes 主要コンポーネント:
リソース種別:Pod, ReplicaSet, Deployment, StatefulSet, DaemonSet, Job, CronJob, Service, Ingress, ConfigMap, Secret, PersistentVolume, PersistentVolumeClaim, Namespace, Role, ClusterRole, NetworkPolicy など。
代替・周辺
- Podman:デーモンレス、rootless、systemd 統合
- LXC / LXD:OS コンテナ(≒軽量 VM)、Canonical
- rkt:CoreOS、終息
- Nixery, Bazel:再現可能ビルド
- gVisor(Google):ユーザ空間カーネル、セキュリティ特化
- Kata Containers:VM と見分けつかない強い分離
デスクトップOSの詳細比較
Windows
Microsoft が 1985 年に MS-DOS 上のシェルとして発売。1995 の Windows 95 で大衆化、2000 年の Windows NT ベース化でモダン OS に。
Windows のエディションと歴史
【図17】Windows 系統図:
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 技術スタック:
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 デスクトップ
デスクトップ市場では Windows や macOS に比べると少数派だが、開発用途、研究用途、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
Android
Google 主導、Open Handset Alliance 発足(2007)、2008 年に HTC Dream 発売。現在は世界で最も広く使われているモバイル OS の一つである。
Android のアーキテクチャ
【図14】Android アーキテクチャ:
この図では、Android が「アプリ層 → フレームワーク → ランタイム / ネイティブライブラリ → HAL → Linux カーネル」という多層構造で成り立つ点を見る。
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 分離
ここで ANR は Application Not Responding の略で、アプリが一定時間応答しないときの警告である。wakelock は端末を不用意にスリープさせないための仕組み、gralloc は GPU/表示系バッファの割り当て基盤である。GKI は Android カーネルの共通部分を標準化し、端末ベンダ固有部分と分離しやすくする取り組みを指す。
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 UI、OnePlus OxygenOS、Xiaomi HyperOS、OPPO ColorOS、HUAWEI EMUI/HarmonyOS:カスタム ROM
- LineageOS、GrapheneOS、CalyxOS:プライバシー・カスタム志向
- Amazon Fire OS、Kai OS:分岐
iOS / iPadOS
Apple が 2007 年発表、iPhone 専用から iPad(iPadOS 13+)、Apple Watch(watchOS)、Apple TV(tvOS)、Vision Pro(visionOS)へと拡張。
iOS のアーキテクチャ
【図15】iOS アーキテクチャ:
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 年にメインラインにマージされた。
- カーネルの多くの を に置換(優先度継承対応)
- 割り込みをスレッド化
- 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 代替を狙った)
- Sprite、LOCUS、Mach(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
チューニング
カーネルパラメータ
/etc/sysctl.conf、sysctl -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 の歴史はコンピュータハードウェアの進化と不可分です。五世代に分けて辿ります。
第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。
AmigaOS、Atari TOS、MS 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: iPhone、2008: Android:モバイル OS 時代到来。
2008: Google Chrome OS:Web ベース。
2013: Docker:コンテナ大衆化。
2014: Kubernetes:クラウドオーケストレーション標準。
2020: Apple Silicon(M1):Mac 完全 ARM 移行。
2022: Rust in Linux:Linux カーネルに初めて C 以外の言語が入る。
2023: Windows 11 AI 統合、Copilot。
2024〜: Generative AI 統合 OS:Microsoft Copilot+, Apple Intelligence, Android AI 機能。
詳細年表(選抜)
現代的トレンドと将来展望
Rust in the Kernel
2022 年、Linux 6.1 で初めて Rust のサポートが入った。段階的に:
- 6.1: 基本インフラ
- 6.2: Rust バインディング
- 6.6: NVMe ドライバ実装進行
- 今後:ネットワークドライバ、ファイルシステム
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。ポータブル、サンドボックス、高速。「OS 非依存のアプリコンテナ」となりうるか。
機密計算(Confidential Computing)
- Intel TDX、AMD SEV-SNP、ARM CCA:VM メモリをハードウェア暗号化
- Google Cloud Confidential VM、Azure Confidential Computing、AWS Nitro Enclaves
- 金融、ヘルスケア、主権クラウドで需要増
メモリタイプの多様化
- CXL(Compute Express Link):メモリをネットワーク的にプールし、複数 CPU で共有
- HBM3/HBM4、DDR6:帯域爆増
- Persistent Memory(3D XPoint、終息)、NVRAM
AI / LLM 統合 OS
- Apple Intelligence:M/A シリーズ Neural Engine + プライベートクラウド
- Microsoft Copilot+ PC、Recall:NPU 必須化
- Android AICore、Gemini Nano:オンデバイス LLM
- 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 や 。
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 | ファイルサイズ制限超過 |
補足
第6章 オペレーティングシステム
この章が実務で役立つ場面
- プロセス異常終了、OOM、権限エラーの調査
- ファイル I/O やソケット I/O の理解
- コンテナや Linux 上のアプリの挙動理解
6.1 OS の役割
OS は、アプリケーションとハードウェアの間に立ち、
- プロセス管理
- メモリ管理
- ファイル管理
- デバイス管理
を行います。
【図11】OS の立ち位置:
6.2 プロセスとスレッド
プロセス
独立した実行単位です。通常は独自の仮想メモリ空間を持ちます。実行中の位置を表すプログラムカウンタやスタックポインタ、レジスタ群といった「いまどこを実行しているか」の状態も含めて考えます。
スレッド
同じプロセス内で資源を共有しながら並行に動く実行単位です。複数のスレッドは同じコード領域やヒープを共有できますが、それぞれが自分のレジスタ状態やスタックを持ちます。
【図12】プロセス内のスレッド構造:
直感としては、
- プロセス = ひとつの独立した作業部屋
- スレッド = その部屋の中で同時に動く作業者
です。部屋が分かれていれば勝手に机の上を触られにくい一方、同じ部屋の作業者どうしは速く連携できる代わりに、ぶつかりやすくもなります。
6.3 システムコール
アプリケーションは、OS の機能を直接たたくのではなく、システムコールを通じて使います。
例:
openreadwriteforkexec
fork は現在のプロセスを複製して子プロセスを作る操作です。Linux では copy-on-write が使われるので、「最初から全部のメモリを丸ごとコピーする」と理解すると少しずれます。まずは同じ内容を共有し、書き込みが起きたところから実体化していきます。
exec は「いまのプロセスの中身を別のプログラムに入れ替える」操作です。新しいプログラムでスタックやヒープも初期化されます。Unix 系でよく見る fork → exec という流れは、
- まず子プロセスを作る
- その子を別プログラムへ置き換える
という二段階です。
【図13】fork と exec の流れ:
6.3.1 ファイル記述子という共通の窓口
Unix 系 OS では、ファイル、パイプ、ソケットなど多くの資源が「ファイル記述子」という共通の窓口で扱われます。read() は「ファイルから読む関数」というより、ファイル記述子から読む関数 です。
この見方を持つと、
- ファイル I/O
- パイプ通信
- ソケット通信
が、OS から見るとかなり似た形で扱える理由が見えてきます。
6.3.2 mmap はなぜ大事か
mmap はファイルやデバイスをメモリ空間へ写像する仕組みです。これにより、アプリケーションは「読む API を何度も呼ぶ」代わりに、「メモリを読むように」ファイル内容へアクセスできます。
直感としては、
read= データをコピーして受け取るmmap= その内容がある領域を自分のアドレス空間へつなぐ
という違いです。
【図14】mmap の概念:
6.4 スケジューリング
OS は「いまどの実行主体に CPU を使わせるか」を決めます。
考えるべき観点:
- 公平性
- 応答性
- 優先度
- リアルタイム性
6.4.1 スケジューリングを日常の比喩で見る
スケジューリングは、1 台のコピー機を複数人で使う状況に似ています。
- 1 人が長く占有しすぎると不公平
- 短い作業は早く終わらせたほうが体感がよい
- 締切のある仕事は優先したい
このバランスを取るのが OS です。
サーバ OS、デスクトップ OS、リアルタイム OS で重点が違うのも自然です。サーバでは throughput、デスクトップでは応答性、リアルタイムでは期限遵守がより重要になります。
6.5 コンテキストスイッチ
CPU がある実行主体から別の実行主体へ切り替わるとき、状態保存と復元が必要です。これがオーバーヘッドになります。
【図15】コンテキストスイッチの流れ:
6.6 仮想メモリ
各プロセスに「連続して広いメモリ空間があるように見せる」仕組みです。実際にはページ単位で管理されます。
仮想メモリの利点:
- プロセス隔離
- 保護
- 見通しのよいアドレス空間
- ディスクとの連携による大きな見かけの空間
OS の観点では、仮想メモリは単なる「ごまかし」ではありません。物理メモリの複雑さを隠しつつ、必要なページだけを主記憶に置く demand paging と、プロセス間の保護や共有を両立するための中心的な仕組みです。
【図15-2】仮想アドレスから物理メモリまで:
6.7 ページとページフォルト
メモリはページという小さな単位で管理されます。必要なページがまだ物理メモリへ載っていないと、ページフォルトが起きて OS が対応します。
【図16】ページフォルトの処理フロー:
ページフォルトという名前は少し怖く見えますが、実際には「必要になったので今読み込む」という正常系の動作も多いです。異常になるのは、アクセス権がない場所を読もうとした、存在しない領域を触った、などのケースです。
6.8 ファイルシステム
ファイルシステムは、ストレージ上のデータを
- ファイル
- ディレクトリ
- パス
- 権限
として扱えるようにします。
6.8.1 永続化とジャーナリング
ファイルシステムで難しいのは、「途中で電源が落ちても壊れにくくすること」です。
そこで使われる考え方の1つが ジャーナリング です。これは、いきなり本体を書き換える前に、
- これから何を変えるかを書き残す
- 本体を更新する
- 完了したら記録を確定する
という順で進める方法です。
これにより、クラッシュ後にも「どこまで終わったか」を追いやすくなります。データベースのログやトランザクションとも発想が似ています。
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 に関する問題の切り分け:
例題1: read() がライブラリ関数ではなく OS の機能にも関係するのはなぜか。
解説: 実際のファイルやデバイスアクセスは OS が管理しているからです。
例題2: プロセスとスレッドの最も大きな違いを一文で述べよ。
解説: 通常、プロセスは独立したメモリ空間を持ち、スレッドは同じプロセス内でそれを共有します。
例題3: ページフォルトは必ず異常終了を意味するか。
解説: 意味しません。必要なページを読み込む正常なページフォルトもあります。
6.13 練習問題
- OS の4つの主要責務を挙げよ。
- 仮想メモリの利点を1つ述べよ。
forkとexecはそれぞれ何をするか。- コンテキストスイッチにコストがかかる理由を一文で述べよ。
6.14 練習問題の答え
- プロセス管理、メモリ管理、ファイル管理、デバイス管理
- 例: プロセス隔離、広い見かけの空間
forkは複製、execは新しいプログラムへ置換- 状態保存と復元が必要だから
6.15 ユースケース
Web サーバ
- プロセスやスレッドで同時接続をさばく
- ファイルとソケットを扱う
- メモリ管理とスケジューリングの影響を受ける
コンテナ
- 名前空間や cgroups によって資源を分離
- OS の仕組みの上に乗っている
まとめ
オペレーティングシステムは、資源管理、抽象化、分離を担う土台です。プロセス、メモリ、ファイル、I/O、仮想化までをまとめて見ると、アプリケーションの下で何が起きているかが立体的に見えてきます。