OS
目次
- 概要
- OSとは何か
- OSの定義と哲学
- OSの主要機能
- OSのアーキテクチャ
- カーネルモードとユーザーモード
- システムコールとABI
- Linuxアーキテクチャの詳細
- コアコンポーネント
- ブートプロセスと初期化
- プロセス管理
- スレッドと並行性
- CPUスケジューリング詳細
- 同期機構とプロセス間通信
- デッドロック・飢餓・レースコンディション
- メモリ管理
- ファイルシステムとI/O
- ストレージ管理とRAID
- デバイス管理とドライバ
- ネットワーキング
- セキュリティ
- 仮想化
- コンテナ技術
- デスクトップOSの詳細比較
- モバイルOS
- リアルタイムOSと組み込みOS
- 分散OS・クラウドOS
- OSのパフォーマンス分析とチューニング
- OSの歴史
- 現代的トレンドと将来展望
- 実践リファレンス
- 補足
- まとめ
- 参考文献
概要
初心者から大学院レベルまでの包括的解説
現代のコンピュータシステムは、アプリケーションからクラウドインフラ、モバイル端末、IoTまでのすべてがOSの上に成り立っています。この章では、OSの理論・実装・歴史・最新動向を体系的に整理します。
この章は、OSを「プロセス・メモリ・ファイル・I/O・ネットワークをどう安全かつ効率よく共有するか」という視点で理解するための全体地図です。定義や理論だけでなく、Linuxを軸に実装や観察のしかたまでつなげます。
この章の対象
この章は次の読者を想定しています。
- 初心者向け: 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とは何かを「教科書的定義」と「実用上の役割」の両方から把握する章です。ここでは「リソース管理者」「ハードウェア抽象化層」「仮想マシン提供者」の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はこれらを抽象化し、プログラマが扱いやすい「仮想計算機」を提供する。 というシステムコールは、内部的にはセクタ計算、キャッシュ参照、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の主要機能
OSが提供する機能は10以上ありますが、「プロセス」「メモリ」「ファイル」「I/O」「ネットワーク」の5つを押さえればほぼ全体像が見えます。
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のアーキテクチャ
「モノリシック」「マイクロカーネル」「ハイブリッド」の3つが主要パターンです。Linuxはモノリシック、macOS/Windowsはハイブリッドという程度を押さえれば十分です。
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) が提唱した設計。各層が下位層のみを呼び出し、逆方向の依存を禁止する。
教育的価値は高いが、層の厳密な区切りが実装と性能を犠牲にするため、純粋な層型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)
システムユーティリティとデーモン
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
プロセス管理
プロセスは「実行中のプログラム」です。複数のプロセスが同時に動いて見えるのは、OSが高速で切り替えて(コンテキストスイッチ)いるからです。
プロセスとは
プロセス は実行中のプログラムの動的実体であり、以下を保持する:
- アドレス空間:テキスト(コード)、データ、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のプロセスモデル
fork()がない:CreateProcess()は一度に新プログラムを起動する。- プロセス作成が高コスト:スレッド作成の方が推奨される(Windowsでの軽量並行処理の伝統)。
- Job Object:プロセスグループを包括的に管理。cgroup的役割。
- プロセスのハンドル:オブジェクトマネージャで管理、参照カウント。
スレッドと並行性
スレッドは「プロセスの中で並行に走る軽量な実行単位」です。プロセスより起動が速く、メモリを共有できるため、並列処理や非同期I/Oの基盤になります。
スレッドとは
スレッド は同一プロセスのアドレス空間を共有する実行の流れ。プロセスが「家」なら、スレッドは「その中で同時に活動する人々」。
| 特性 | プロセス | スレッド |
|---|---|---|
| アドレス空間 | 独立 | 共有 |
| ファイルディスクリプタ | 独立 | 共有 |
| スタック | 一つ | 各スレッド固有 |
| レジスタ | 一つ | 各スレッド固有 |
| シグナルマスク | 共有 | 各スレッド固有 |
| 生成コスト | 高(数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. ソケット
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(メモリ管理ユニット)が協力して、仮想→物理への変換、分離、保護、拡張(スワップ)を実現しています。
現代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になる状態。
対策:
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)
同サイズのオブジェクト(, 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 (遅)
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
デバイス管理とドライバ
デバイスの分類
- キャラクタデバイス(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プログラムをカーネル内で実行する革新的機構。
仕組み:
- 検証器(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;
}
名前空間とネットワーク分離
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)」の原則に立っています。認証・認可・サンドボックス・暗号化・監査を重ねがけして、どこかが破られても他で食い止めます。
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シリーズ内蔵
仮想化
仮想化は「1台の物理マシンで複数のOSを同時に動かす」技術です。クラウドの基盤はすべてこれです。コンテナよりも分離が強く、オーバーヘッドは少し大きくなります。
仮想化 vs コンテナの比較:
| 項目 | 仮想化 | コンテナ |
|---|---|---|
| 分離レベル | 完全(別カーネル) | 論理的(共有カーネル) |
| 起動時間 | 数秒 | 数ミリ秒 |
| メモリ効率 | 低(ゲストOS込) | 高 |
| 同一ホスト上での数 | 数十個 | 数千個 |
| OS 多様性 | 高(Windows/Linux/BSD可) | Linux が中心 |
| デバッグ / アクセス | ゲストOSに完全アクセス | 限定的(namespace隔離) |
仮想化の種類
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)
マイクロVM (Lightweight VMs)
コンテナの速度とVM の分離を両立する新世代技術。クラウドネイティブ向け。
- Firecracker(AWS):Linux カーネル 5.10+、最小メモリ 3MB、起動 125ms、Kubernetes Pod 代替、Lambda/Fargate 基盤
- Kata Containers:OCI 準拠、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仮想化スタック:
メモリ仮想化
- シャドウページテーブル: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のカーネルを共有するため、仮想マシンより起動が速く、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】コンテナランタイムの階層:
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の詳細比較
世界で使われているデスクトップOSは事実上Windows、macOS、Linuxの3つです。それぞれ設計哲学・ターゲット層・パッケージ管理が大きく異なります。
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
モバイルOSはAndroidとiOSが中心です。AndroidはLinuxカーネルベース、iOSはXNUベースで、どちらも省電力・セキュリティ・バッテリー管理に特化した設計です。
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年にメインラインにマージされた。
産業ロボット、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
Linuxでの初動調査導線
Linuxの障害調査では、いきなりprofilerを回すより、まず「どの層で詰まっているか」を粗く切り分ける方が速い。たとえば次の順で見ると、CPU・メモリ・I/O・ネットワーク・サービス状態のどこに寄っているかが見えやすい。
systemctl status <service>で対象サービスの生死と直近エラーを確認するjournalctl -u <service> -n 100とjournalctl -k -n 100で、アプリログとカーネルログを分けて読むtop,vmstat 1,iostat -xz 1,ss -tulpnで資源の詰まり方を把握する/proc/<pid>/status,/proc/<pid>/smaps,/proc/<pid>/fdで個別プロセスの実態を見る- 必要なら
straceやperf、eBPFへ進む
この流れの利点は、「サービスが落ちているのか」「生きているが待たされているのか」「CPUバウンドなのかI/Oバウンドなのか」を、早い段階で誤らずに済むことにある。
strace と perf の使い分け
Linuxでは strace と perf を混同しやすいが、見ている層が違う。
straceシステムコールの出入りを見る。openat,read,connect,futex,epoll_waitが大量に出ているか、どこでENOENTやEACCESが返っているか、といった「OSとの境界」を追うのに向く。perfCPU時間がどこで使われているかを見る。関数単位の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.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の歴史はハードウェアの進化と歩調を合わせて発展してきました。バッチ処理 → タイムシェアリング → 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。
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ベース。
2014: Kubernetes:クラウドオーケストレーション標準。
2020: Apple Silicon(M1):Mac完全ARM移行。
2022: Rust in Linux:Linuxカーネルに初めてC以外の言語が入る。
2023〜: AI機能のOS統合:Microsoft Copilot、Apple Intelligence、AndroidのオンデバイスAI機能などがOS体験へ入り始める。
詳細年表(選抜)
現代的トレンドと将来展望
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 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:オンデバイス処理とPrivate Cloud Computeを組み合わせる設計
- Microsoft Copilot+ PC:NPUを前提にしたクライアント機能拡張
- 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 や 。
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の役割を分解して見ます。
この章が実務で役立つ場面
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.15ユースケース
Webサーバ
コンテナ
まとめ
オペレーティングシステムは、資源管理、抽象化、分離を担う土台です。プロセス、メモリ、ファイル、I/O、仮想化までをまとめて見ると、アプリケーションの下で何が起きているかが立体的に見えてきます。
参考文献
公式・標準
- POSIX.1-2024 Standard
- CFS Scheduler
- Control Group v2 Documentation
- EEVDF Scheduler Documentation
- ext4 Documentation
- Kubernetes Documentation
- KVM Documentation
- Linux CXL Documentation
- Memory Management
- sched_ext documentation
- The Linux Kernel Documentation
- WSL Documentation
- XFS Documentation
- Microsoft Learn - Windows Kernel
- NTFS Overview
- Sysinternals
- Windows Internals
- OCI Runtime Specification
- POSIX Threads Programming (LLNL)
- The Linux Kernel Archives
論文
講義・記事
- Kernel Programming Guide (Apple Archive)
- xv6: a simple Unix-like teaching operating system
- Foundations of the C++ Concurrency Memory Model
- Apple Platform Security Guide
書籍
- Computer Systems: A Programmer’s Perspective
- Operating Systems: Three Easy Pieces (OSTEP)
- Linux Insides
- Little Book of Semaphores
- Operating System Concepts
- 30日でできる!OS自作入門
- Goならわかるシステムプログラミング
- LinuxカーネルHacks
- 作って理解するOS
- 詳解Linuxカーネル 第3版
- Understanding the Linux Kernel
解説・補助
- RISC-V Privileged ISA
- APFS Reference
- Intel TDX Overview
- AMD SEV-SNP Documentation
- Android Runtime (ART)
- AOSP Kernel Overview
- Btrfs Documentation
- OpenZFS Documentation
- QEMU Documentation
- wasmtime Documentation
- Xen Project Documentation
- runwasi
- XNU Source Code
- Android Open Source Project
- Cilium
- eBPF.io
- Firecracker
- io_uring(7)
- Kernel Index (LWN)
- KernelNewbies
- LWN.net
- Modern Operating Systems
- namespaces(7)
- Open Container Initiative
- Operating Systems: Design and Implementation
- pthreads(7)
- Rust for Linux
- seL4
- The Design and Implementation of the FreeBSD Operating System
- WASI.dev Interfaces
- Writing an OS in Rust