記事

CSロードマップ 第7回 — OSアーキテクチャ入門:Unix、NT、XNUの分かれ道

CSロードマップ 第7回 — OSアーキテクチャ入門:Unix、NT、XNUの分かれ道
前提知識 — 先にこちらをご確認ください
TL;DR — 要点まとめ
  • 3つのOSの違いは「技術選択」ではなく「歴史的な経路依存性」である — 1970〜80年代のUnix、VMS、NeXTSTEPにまつわる決定が今日のLinux、Windows、macOSを形づくった
  • カーネル構造が異なる(Linuxはモノリシック、Windows NTはハイブリッド、macOS XNUはMachマイクロカーネルの上にBSDを重ねた二重構造)
  • macOSはGrand Central Dispatchでスレッド抽象化を、Apple SiliconでP/E異種コアと16KBページを、Rosetta 2でハードウェアTSOモードを導入した
  • 実行バイナリ形式(ELF/PE/Mach-O)がそもそも違うため、ゲームのマルチプラットフォームビルドではクロスコンパイルが複雑になる
Visitors

Hits

はじめに:なぜOSから始めるのか

ステージ1ではデータ構造とメモリを扱いました。配列と連結リスト、ハッシュテーブル、木とグラフ、そしてヒープまで — すべて「データをどう整理するか」の話でした。

ステージ2の問いは少し違います。

「2つのスレッドが同じ変数を使うと、なぜプログラムは時々だけ死ぬのか?」

この問いに答えるには、プログラムがどう実行され、誰がCPUを分け与え、メモリがどう保護されるかを知る必要があります。それがオペレーティングシステム(OS)の役割です。

ところがOSの勉強を始めるとすぐに奇妙な壁に当たります。教科書には「プロセスはPCBを持つ」というような抽象的な説明が書かれています。しかし実際にmacOSでpsを打ち、Windowsでタスクマネージャーを開いてみると、3つのOSの世界はまったく違って見えます。

  • Linuxではプロセス生成がfork()の2文字で終わります
  • WindowsではCreateProcess()に12個のパラメータが並びます
  • macOSでは同じfork()を使っても、その下にはMachカーネルというまったく別のものがあります

この3つのOSの違いは技術的な選択ではなく、歴史の産物です。1969年のUnixの誕生、1977年のBerkeleyの分岐、1989年のNeXTSTEPの賭け、1993年のWindows NTの設計 — これらの決定が、今日あなたがUnityゲームをビルドするときに.exeが出るか.appが出るかを決めています。

ステージ2の最初の回は本格的な理論に入る前に地図を描く作業です。各OSがどういう血統から来て、なぜ互いに違う姿になり、ゲーム開発者にとってどんな違いがあるかをざっと見ます。次の回からはプロセス、スレッド、スケジューリングといった具体的なテーマに入っていきますが、そのたびに「この概念はLinuxではA、WindowsではB」と比較できるようにするには、まず3つのOSの骨格を知る必要があります。

とくにMacユーザーの読者のために、macOS固有のセクションを詳しく扱います。XNUカーネルの独特な二重構造、Grand Central Dispatchの設計思想、Apple Siliconのハードウェア上の仕掛けまで — 他のOS本では周辺に追いやられる話題が、ここでは主役です。


Part 1:3つのOSの血統 — 1969年の決定が2026年をつくる

Unixの誕生 (1969)

Ken ThompsonとDennis Ritchie (1973) Ken Thompson(左)とDennis Ritchie(右)、1973年。UnixとC言語の創始者たち。出典:Jargon File (Public Domain)

すべての物語は1969年、アメリカ・ニュージャージー州のAT&T Bell Labsで始まります。Ken ThompsonDennis Ritchieは、GE-645というメインフレーム上で走るMulticsという巨大なOSプロジェクトで挫折を味わっていました。Multicsは野心的すぎて、遅すぎて、複雑すぎたのです。

Bell Labsの片隅で放置されていたPDP-7というコンピュータをThompsonは見つけ、そこでMulticsの不要な複雑さを削ぎ落とした単純なOSを趣味で作り始めました。名前は「Multi-」の代わりに「Uni-」を付けて UNICS (Uniplexed Information and Computing Service)。のちに名前がUnixに落ち着きます。

Unixの設計原則は後に「Unix哲学」と呼ばれるようになります:

  1. 1つのことだけをうまくやれ (Do one thing and do it well)
  2. すべてはファイルである (Everything is a file)
  3. プログラムを組み合わせよ(パイプ|で出力を次の入力に)
  4. テキストが汎用インターフェースである

1973年、RitchieはUnixをC言語で書き直します。これが決定打でした。それまでOSはアセンブリ言語でしか書けず、他のハードウェアに移植できなかったのですが、Cで書かれたUnixは移植可能なOSの時代を開きました。

1970年代後半、UnixのソースコードはAT&Tが低価格のライセンスで大学に配布します。特にUC Berkeleyが熱心に受け入れ、学生たちはUnixを修正して配布し始めます。ここが分岐点です。

BSD分岐:Berkeleyの学生たち

1977年からBerkeleyが配布したUnix派生版をBerkeley Software Distribution (BSD)と呼びます。BSDは既存のUnixにはなかった多くの機能を追加しました:

  • TCP/IPネットワークスタック(1983、インターネットの基礎)
  • Berkeley Sockets API(今でもネットワークプログラミングの標準)
  • 仮想メモリの改善
  • Fast File System (FFS)

1980年代半ばにはBSDはUnixの事実上の標準の1つになります。しかしAT&Tがライセンス訴訟を起こしBerkeleyは長い法廷闘争に巻き込まれ、その結果AT&Tコードを完全に排除した自由なBSDが生まれます。これがFreeBSD、NetBSD、OpenBSDのルーツです。

重要な点:BSDは完全にオープンソースで、ライセンスがGPL(Linux)よりはるかに自由です。このため後にAppleがmacOSの基盤としてBSDを選ぶことになります。GPLならAppleは自社の修正内容をすべて公開しなければならなかったはずですが、BSDライセンスにはその義務がなかったからです。

NeXTSTEP → macOS:Steve Jobsの帰還

NeXTcubeコンピュータ (1990) NeXTcube (1990)、Computer History Museum所蔵。このコンピュータに搭載されたNeXTSTEPが今日のmacOSのルーツだ。写真:Michael Hicks, CC BY 2.0

1985年、Appleを追い出されたSteve JobsはNeXTという会社を立ち上げます。NeXTの目標は「大学と研究者のための高級ワークステーション」でした。そのコンピュータに搭載するOSがNeXTSTEP (1989) です。

NeXTSTEPの設計は独特でした:

  • カーネルはMachマイクロカーネル(Carnegie Mellon Universityで開発)
  • その上にBSD Unixレイヤを重ねてPOSIX互換性を提供
  • アプリケーションフレームワークはObjective-Cで書かれたCocoa(当時の名前はAppKit)

当時この構造は学界で流行していた「マイクロカーネルが未来だ」という思想の実践でした。しかしNeXTコンピュータは商業的に失敗し、会社は生き残るためにハードウェアを諦め、NeXTSTEPを他のハードウェアに移植する方向に転換します(1993〜)。

1996年、驚くべきことが起こります。AppleがNeXTを買収したのです。当時Appleは Mac OS 9の後継となる次世代OSを作ろうとした「Copland」プロジェクトが失敗し、基盤技術がありませんでした。Appleは外部からOSを買うことにし、BeOSとNeXTSTEPで迷った末にNeXTSTEPを選びます。金額はおよそ4億ドル

Steve JobsはNeXTとともにAppleに戻り、1997年に暫定CEOに復帰します。そしてNeXTSTEPがmacOSの基盤になりました。

  • 1999:Mac OS X Server 1.0(NeXTSTEPベース)
  • 2001:Mac OS X 10.0 Cheetah — 一般ユーザー向け
  • 2007:iPhone OS(Mac OS Xの縮小版)
  • 2016:「Mac OS X」から「macOS」に改名

つまり、今日あなたのMacBookで動いているmacOSのカーネルは、1980年代のNeXTが1990年代のAppleに売ったもので、そのルーツはCarnegie Mellon Universityで行われていたMach研究プロジェクトまで遡ります。30年以上前の設計がまだ生きているのです。

Linux:フィンランドの大学生の趣味プロジェクト (1991)

LinuxCon Europe 2014でのLinus Torvalds Linus Torvalds、LinuxCon Europe 2014。23年前の趣味プロジェクトが世界のインフラの基盤になったことを振り返っている最中。写真:Krd, CC BY-SA 4.0

1991年、フィンランドのヘルシンキ大学のLinus Torvaldsは、学校でOSの講義を受けながらAndrew Tanenbaumが教育用に作ったMinixを使っていました。Minixは優れた教育用OSでしたが、商用ライセンスで利用が制限されており、Linusは自宅の386 PCでもっと自由に使えるものが必要でした。

それで趣味でOSを作り始めます。8月25日、comp.os.minixニュースグループに投げたメッセージが有名です:

“Hello everybody out there using minix — I’m doing a (free) operating system (just a hobby, won’t be big and professional like gnu)…”

「大きくもなく、プロフェッショナルでもないだろう」と言っていたその趣味プロジェクトが、30年後に世界の大多数のサーバー、スマートフォン、スーパーコンピュータで動いています。

Linuxは最初からGPLライセンスを採用し、世界中の開発者が貢献できるモデルを築きました。そしてGNUプロジェクトのユーザーランドツール(gcc、bash、coreutilsなど)と組み合わさって完全なOSになりました — 厳密にはGNU/Linuxと呼びます。

Linuxの決定的な特徴 — カーネル構造の面で:

  • モノリシックカーネル:Unixの伝統に従い、カーネルにすべての機能(ファイルシステム、ネットワーク、ドライバ、メモリ管理)を詰め込む
  • Tanenbaumが「マイクロカーネルが優れている」と批判し、Linusが反論した1992年の論争はOSの歴史上有名です
  • 30年が経った今、Linuxは部分的にモジュール化されたモノリシックカーネルに進化しました(カーネルモジュール機能)

VMS → Windows NT:Dave Cutlerの逆襲

ここまでの話はすべてUnix系です。ところがWindowsはUnixとまったく違う血統です。

1970年代、Digital Equipment Corporation (DEC) はミニコンピュータ市場の強者でした。彼らのOSはVMS (Virtual Memory System) で、大型サーバ向けの高信頼性OSでした。VMSの主任設計者がDave Cutlerです。

1988年、DECで新プロジェクトが中止になると、Dave Cutlerはチームを率いてMicrosoftに移籍します。Microsoftのビル・ゲイツから「OS/2の次の32ビットOSを作ってほしい」と提案があったからです。

CutlerはWindows NT (NT = New Technology) を設計します。内部的にVMSの多くのアイデアを持ち込みました — VMSの各文字を1つずつ後ろにずらすとWNTになるというジョークがあるほどです(V→W、M→N、S→T)。

Windows NTの主な特徴:

  • ハイブリッドカーネル:マイクロカーネルのようにサブシステムを分けたが、性能のために多くをカーネル空間に置いた
  • POSIXサブシステム、OS/2サブシステム、Win32サブシステムが分離 — 理論上、他のOSのAPIを同時に支援できた
  • ユニコード優先:設計段階からUnicode(UTF-16)を前提
  • マルチアーキテクチャ対応:x86、MIPS、Alpha、PowerPC(初期は)

1993年にWindows NT 3.1がリリースされ、NT 4.0、Windows 2000、XP、7、10、11まですべて同じNTカーネル系譜に属します。つまり、あなたがWindows 11でUnityをビルドするときに走っているカーネルのルーツはDEC VMS(1977)に連なります。

一方、Windows 95、98、MEはまったく別の血統でした — MS-DOSベースのWindows 1.0〜3.1系譜。Microsoftは2001年のWindows XPでこの2つの系譜をNT側に統合し、DOS系譜を終わらせます。

血統ツリー

ここまでの話を可視化すると以下のようになります。

3つのオペレーティングシステムの血統 — 1969〜2026 Unix系 VMS系 Unix (1969) VMS (1977) BSD (1977) Minix (1987) System V (1983) NeXTSTEP (1989) Linux (1991) macOS (2001) Android / Server Windows 11 Windows NT (1993) Windows 2000 / XP macOSはBSD → NeXTSTEP経路で、LinuxはMinixの影響で、Windowsはまったく別のVMS経路で。 Unixは技術ではなく 思想とAPI を残した。VMSはDave Cutlerとともに Microsoft へ移った。

Part 2:3つのOSの設計思想

血統が違えば思想も違います。同じ問題 — 「メモリ不足時にどう処理するか」 — に対して3つのOSが違う反応をする理由はここにあります。

Linux:開放性と性能

Linuxの文化は「ハック可能性」に最高の価値を置きます。

  • すべてが公開:カーネルソース全体がGPLで公開され、誰でも読んで修正できる
  • ファイルシステムを通した制御/proc/sysファイルシステムでカーネル状態をファイルのように読み書きできる
    • 例:cat /proc/meminfoでメモリ状態確認、echo 3 > /proc/sys/vm/drop_cachesでキャッシュクリア
  • テキスト優先:設定ファイルはほぼすべてテキスト。バイナリ設定DB(レジストリ)がない
  • 性能優先:互換性より性能。例えばABI互換性は保証するがカーネル内部APIはいつでも変わりうる
  • 多様性の受容:ディストリ(Ubuntu、Arch、Fedora、Alpine…)ごとに違う思想を許容

短所:断片化。「Linux」と一括りにするが、UbuntuとAlpineは別のOSに近いほど違います。またデスクトップUXは相対的に弱い。

Windows:下位互換性の極致

Microsoftの文化は「お客が10年前にお金を払ったプログラムが今日も動かなければならない」です。

  • 下位互換性がほぼ神聖不可侵:Windows 95用プログラムがWindows 11でもほぼ実行できる
    • 有名な逸話:Windowsには特定の有名ゲーム(SimCity)のバグを回避するコードがカーネルに入っています。ゲームが解放済みのメモリを読むバグがあり、Windows 95からWindows NTへ移行した際にそのメモリが即座に回収されるとSimCityがクラッシュしたため、Microsoftは「SimCityが実行中ならメモリ解放を遅らせるコード」をWindowsに追加しました(Raymond Chenのブログに記録あり)
  • 強力なバイナリAPI:Win32 APIは30年間事実上そのまま。COM、.NETなどの上位レイヤも下位互換を維持
  • レジストリ:システム全体の設定DB。テキストファイルではなく構造化されたキー・値ストア
  • GUI優先:コマンドラインよりGUIが先に設計された。PowerShellは後発
  • エンタープライズ中心:Active Directory、Group Policyなど大規模組織管理機能が非常に強力

短所:下位互換性のためのコードが累積してカーネルが重くなり、セキュリティ面が広がります。30年前のAPIのバグが2025年にも消えない理由です。

macOS:統制された体験とハードウェア統合

Appleの文化は「ハードウェアとソフトウェアを一緒に設計する」です。

  • 垂直統合:AppleはCPU(Apple Silicon)、OS(macOS)、GUI(Aqua)、アプリケーションフレームワーク(Cocoa)、開発ツール(Xcode)をすべて自社で作る
  • 単一の公式経路:Linuxのような多数のディストリもなく、Windowsのような複数のサブシステム共存もない。公式のやり方が1つ
  • 急進的な切り替えの受容:Appleは思い切って旧バージョンを捨てる
    • PowerPC → Intel(2006、Rosetta 1で移行)
    • 32ビット → 64ビット(2019 macOS Catalinaで32ビットアプリサポート完全撤去)
    • Intel → Apple Silicon(2020、Rosetta 2で移行)
  • ユーザー体験優先:アニメーション、フォントレンダリング、カラー管理などがOSレベルで一貫
  • セキュリティ統制:Gatekeeper、notarization、SIPなど階層的なセキュリティ体系ですべてのアプリをAppleの検証下に置く

短所:自由度が低く、Appleがサポートを打ち切ると手立てがありません(例:7年以上前のMacは最新のmacOSをインストール不可)。またAppleエコシステム外との互換性は副次的。

思想比較表

基準LinuxWindowsmacOS
中核価値開放性、性能互換性、エンタープライズ統合、体験
カーネル修正誰でも可能MicrosoftのみAppleのみ
バイナリ互換性カーネルABIのみ保証30年維持大転換時Rosettaで
ユーザーインターフェース選択肢多(GNOME、KDE…)Windows Shell固定Aqua固定
設定保存テキストファイルレジストリplist(XML/バイナリ)
パッケージ管理ディストリ別(apt、dnf、pacman)MSI/EXE/StoreApp Store / Homebrew / dmg
主な用途サーバ、組み込み、開発者企業、ゲーム、一般消費者クリエイティブ、開発者、一般
ゲーム貧弱(Protonで改善中)最高中程度(Metal + Apple Silicon)

Part 3:カーネル構造 — モノリシック、マイクロ、ハイブリッド

OSの心臓はカーネルです。カーネルはハードウェアとアプリの間で資源を管理します。ところがカーネルをどう構成するかは1980年代以来OS設計者たちの長年の論争の的でした。

3つの構造

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

カーネル全体が1つの大きなプログラムです。ファイルシステム、ネットワークスタック、ドライバ、メモリ管理などがすべて同じアドレス空間で実行されます。

  • 長所:速い。カーネル内部呼び出しが通常の関数呼び出し
  • 短所:ドライバ1つのバグで全体カーネルがクラッシュ、カーネルが巨大化
  • 代表:Linux、伝統的なUnix、FreeBSD

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

カーネルは最小限の機能だけを持ちます — プロセス、メモリ、IPC(プロセス間通信)。ファイルシステム、ドライバなどはユーザー空間のサーバープロセスに分離されます。

  • 長所:モジュール化、安定性、セキュリティ
  • 短所:IPCコストで遅い(メッセージ伝達がカーネルをもう一度経由)
  • 代表:純粋Mach、MINIX 3、QNX、L4、seL4

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

マイクロカーネルのモジュール化を追求するが、性能のために多くをカーネル空間に置きます。

  • 長所:2つの構造の妥協
  • 短所:「本物のマイクロカーネルではない」という批判
  • 代表:Windows NT、macOS (XNU)

Linux — モノリシックの頂点

Linuxカーネルは巨大です。2024年基準でソースコード3000万行以上。しかし内部的にはモジュール化されていてドライバやファイルシステムをカーネルモジュールとしてロード/アンロードできます。

1
2
3
4
5
6
7
8
# Linuxで現在ロードされているモジュールを見る
lsmod

# モジュールロード
sudo modprobe nvidia

# モジュールアンロード
sudo rmmod nvidia

これらのモジュールは同じカーネルアドレス空間で実行されます。つまり、悪意あるモジュールやバグのあるドライバは全体システムを倒せます。そのためLinuxカーネルモジュールには署名検証、SecureBootといったセキュリティ層が追加されます。

Windows NT — ハイブリッドの実例

Windows NTはExecutiveと呼ばれるカーネル上位層とMicrokernelと呼ばれる下位層に分かれます。ただ「Microkernel」という名前とは裏腹に、実際にはドライバ、ファイルシステム、ネットワークスタックがすべてカーネル空間で実行されます。

Windows NTの階層:

Windows NT 階層構造 User Mode Win32 アプリ · POSIX サブシステム · .NET Kernel Mode Executive · Object Manager · Process Manager · Memory Manager · I/O Manager · Security Reference Monitor Microkernel · Thread Scheduler · Interrupt Handler HAL (Hardware Abstraction Layer) Hardware CPU · メモリ · ディスク · ネットワークカード

特殊な点:Windows NTは初期にPOSIXサブシステムOS/2サブシステムを持っていました。理論的にはPOSIXプログラムがWindowsで修正なしに動けました。しかし実用性が低くPOSIXサブシステムはWindows 8で除去され、代わりにWSL (Windows Subsystem for Linux)がまったく別の方式(Linuxカーネル自体をVMで走らせる)で実装されました。

XNU — Mach + BSD の二重構造

macOSのカーネルはXNUと呼ばれます(”X is Not Unix”)。XNUは2つのレイヤで構成されます:

  1. Mach 3.0 マイクロカーネル(下位):Carnegie Mellon研究由来。タスク、スレッド、メッセージ伝達(Machポート)、仮想メモリを担当
  2. BSDレイヤ(上位):FreeBSDから移植されたUnix実装。プロセスモデル(POSIX)、ネットワークスタック、ファイルシステム(HFS+/APFS)
  3. I/O Kit:ドライバフレームワーク(C++で書かれている)

なぜこんな奇妙な構造なのか?

元々NeXTSTEPは「純粋マイクロカーネル = Mach」の上に「サーバープロセスとしてのBSD」を重ねる構造を試みました。しかしこの方式はとても遅かったのです。ファイルを読むことすらユーザー空間のBSDサーバーとMachカーネルの間のIPCを何度も経由する必要があったからです。

そこで妥協しました:BSDコードをMachと同じカーネル空間に移植。「マイクロカーネル」という建築哲学は破れましたが、性能が確保されました。これが今のXNU — 理論上はマイクロカーネルだが実際にはハイブリッド

3つのカーネル構造の比較 Linux モノリシック ユーザー空間 カーネル空間(1つの巨大なプログラム) ファイルシステム ネットワークスタック ドライバ メモリ管理 スケジューラ IPC ハードウェア Windows NT ハイブリッド ユーザー空間 (Win32, .NET) Executive Object / Memory / I/O Manager Security Reference Monitor Microkernel Layer スケジューラ、割り込み HAL ハードウェア macOS XNU (Mach+BSD) ユーザー空間 (Cocoa, UIKit) BSD Layer POSIX、ネットワーク、ファイルシステム プロセスモデル Mach Microkernel Task, Thread, Mach Port VM、スケジューラ I/O Kit(ドライバ C++) ハードウェア 3つの構造すべてでユーザー/カーネル境界は同じだが、カーネル内部の分割方式が違う。

ちょっと、これは押さえておこう

「マイクロカーネルが理論的に良いのなら、なぜ誰も純粋なマイクロカーネルを使わないのか?」

答えはIPCコストです。マイクロカーネルでファイルを読むには次のような手順になります:

  1. アプリが「ファイルを読んで」というメッセージをカーネルに送る
  2. カーネルがそのメッセージをファイルシステムサーバープロセスに転送
  3. ファイルシステムサーバーがディスクドライバサーバーにメッセージを送る
  4. ディスクドライバが実際にディスクを読み、結果をファイルシステムサーバーに返す
  5. ファイルシステムサーバーがアプリに結果を返す

各ステップごとにコンテキストスイッチ + メッセージコピーが発生します。1980〜90年代のハードウェアではこのコストが耐え難いほどでした。

モノリシックカーネルでは同じ作業が関数呼び出し1回で終わります。

だからほとんどの実用OSは「マイクロカーネル設計思想は受け入れつつ、性能のために妥協」するハイブリッドに収束しました。純粋なマイクロカーネルはリアルタイムシステム(QNX)、セキュリティ重要システム(seL4 — 数学的に検証されたカーネル)のように特殊分野でしか生き残っていません。


Part 4:実行バイナリ形式 — 同じCコード、違う成果物

あなたがC++で書かれたUnityゲームをビルドすると、3つのOSで違うバイナリが出ます:

  • Linux:ELF (Executable and Linkable Format)
  • Windows:PE / PE32+ (Portable Executable)
  • macOS:Mach-O

これらの形式はまったく違います。単に拡張子の違いではなく、ファイル内部構造が違うため、あるOSのバイナリを他のOSで実行することはできません(エミュレータを使わない限り)。

ELF — Linuxの標準 (1988〜)

ELFファイルレイアウト — Linking View vs Execution View Linking View(セクション) リンカ / コンパイラが使用 Execution View(セグメント) ランタイムにローダが使用 ELF Header Program Header Table .text(実行コード) .rodata(定数 / 文字列) .data(初期化グローバル) .bss(0初期化、サイズのみ) .symtab(シンボルテーブル) .strtab(文字列テーブル) .debug_* (DWARF) Section Header Table ELF Header Program Header Table LOAD Segment #1 Read + Execute .text + .rodata LOAD Segment #2 Read + Write .data + .bss (ロードされない) シンボルテーブル、デバッグ情報 プロダクションビルドではstrip またはデバッグ用に保持 Section Header Table(ランタイムでは任意) 同じファイルでもリンカはセクション単位、ローダはセグメント(権限)単位で見る。 プロダクションバイナリはSection Header Tableを省略し、.symtab / .debug_*をstripしてサイズを縮められる。

Executable and Linkable FormatはSystem Vで導入された形式で、今ではほとんどのUnix系(Linux、FreeBSD、Solaris)が使います。

ELFファイルの構造:

ELFファイル構造 (Linux) ELF Header マジックナンバー 0x7f 'E' 'L' 'F' Program Header Table 実行時のメモリマッピング情報 SECTIONS .text 実行コード .rodata 読み取り専用データ(文字列リテラルなど) .data 初期化済みグローバル変数 .bss 0初期化グローバル変数(ファイルにはサイズのみ) .symtab シンボルテーブル .strtab 文字列テーブル .debug_* DWARFデバッグ情報 Section Header Table セクション位置 / 属性情報

ELF確認:

1
2
3
4
5
6
7
8
9
10
$ file /bin/ls
/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), ...

$ readelf -h /bin/ls
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64

PE — Windowsの系譜 (1993〜)

Portable ExecutableはWindows NTで導入された形式です。UnixのCOFF(Common Object File Format)から派生しましたが、Microsoft固有の拡張が多くあります。

PEファイルの構造:

PEファイル構造 (Windows) DOS Header (MZ) 16ビット時代の互換性遺産 DOS Stub "This program cannot be run in DOS mode" PE Signature "PE\0\0" COFF Header CPUアーキテクチャ · セクション数 Optional Header エントリポイント · イメージベース · サブシステム Section Headers SECTIONS .text 実行コード .rdata 読み取り専用データ · インポートテーブル .data 初期化済みグローバル変数 .rsrc アイコン · バージョン情報などリソース .reloc 再配置情報

面白い点:PEファイルの先頭には今なおDOS互換用「MZ」マジックナンバーがあります(MZはDOSの開発者Mark Zbikowskiのイニシャル)。1993年に設計された形式が1981年のDOS互換性文字列を今も持っています。これがWindowsの下位互換性文化を示す代表例です。

Mach-O — macOSの形式

Mach-O (Mach Object)はMachカーネルとともに設計された形式です。NeXTSTEPで始まり、今もmacOS/iOSが使います。

Mach-Oファイルの構造:

Mach-Oファイル構造 (macOS / iOS) Header マジック 0xFEEDFACE (32) / 0xFEEDFACF (64) Load Commands ローダへの指示 LC_SEGMENT メモリセグメント定義 LC_DYLD_INFO 動的リンカ情報 LC_SYMTAB シンボルテーブル LC_LOAD_DYLIB 必要なライブラリ LC_CODE_SIGNATURE コード署名 SEGMENT · __TEXT __text 実行コード __cstring C文字列定数 SEGMENT · __DATA __data 初期化済みグローバル変数 __bss 0初期化グローバル変数 Segment: __LINKEDIT シンボル · 再配置 · 署名

Universal Binary (Fat Binary):1つのファイルに複数のアーキテクチャのMach-Oをすべて収められます。

Universal Binary (Fat Binary) Fat Header 内蔵アーキテクチャ一覧 · 各オフセット Arch 0: x86_64 (完全なMach-O) Intel Mac用 Arch 1: arm64 (完全なMach-O) Apple Silicon用

これが「同一のアプリがIntel MacとM1 Mac両方でネイティブに動く」構造です。2006年のPowerPC→Intel移行でも、2020年のIntel→Apple Silicon移行でも同じ方式で移植が行われました。

マルチプラットフォームビルドでの意味

Unity、Unrealのようなエンジンが「一度作れば複数プラットフォームで動く」と宣伝しますが、実際にはエンジンが内部的に3つの形式に合わせて作り直します。あなたがBuild Settingsでプラットフォームを変えるときエンジンがやっていること:

  • Windows:MSVCまたはclang-clでコンパイル → PE32+生成、Windows SDKリンク
  • macOS:clang/xcodeツールチェーン → Mach-O生成、Cocoaフレームワークリンク(Universal BinaryでIntel+ARM同時)
  • Linux:gccまたはclang → ELF生成、glibcリンク

同じC++コードでも最終バイナリはまったく違うファイルです。そのためWindowsでビルドした.exeをmacOSに持っていっても動きません。

もう1つの落とし穴:ゲームエンジンは動的ライブラリを多用します。

  • Windows:.dll
  • macOS:.dylibまたは.framework(バンドル形式)
  • Linux:.so

各プラットフォーム別に全部別々にビルドする必要があります。Unityネイティブプラグインが Windowsだけ対応するケースが多い理由です。


Part 5:macOS固有の話 — Appleが積み上げたもの

ここからはMacユーザーに特に面白いセクションです。macOSが他のOSと異なるApple固有のシステムたちを深く見ていきます。

XNU誕生の裏話

前でXNUがMach + BSDの二重構造だと言いましたが、その過程には失敗と妥協の歴史があります。

第1段階 (1985〜88) — 純粋Machの夢 Carnegie Mellon UniversityのMachプロジェクトは「BSD Unix機能をマイクロカーネルで再実装する」学術実験でした。Rashid教授と学生たちがMach 2.0を出しましたが、これは「Mach + BSDサーバー」が1つのカーネルに混在した混成構造でした。

第2段階 (1990) — Mach 3.0の試み Mach 3.0は純粋なマイクロカーネルを志向してBSDコードを完全にユーザー空間サーバーに分離しました。理論的には完璧でしたが性能が酷いものでした。OSF/1という商用OSがMach 3.0で出ましたが市場で失敗しました。

第3段階 (1989〜96) — NeXTSTEPの実用的選択 NeXTは最初にMach 2.0をベースにNeXTSTEPを作りました。一部のBSD機能をMachカーネルに直接マージして性能を確保。これがNeXTSTEPのカーネル基盤です。

第4段階 (2000〜) — XNU AppleがNeXTSTEPを取ってmacOSとして作る際、BSD側をFreeBSD 5.xから大幅に更新して持ってきました。この結果がXNU。そのためmacOSでuname -aを打つと”Darwin”が出ますが、Darwin = XNU + BSDユーザーランド = macOSのオープンソース部分です。

1
2
$ uname -a
Darwin MacBook.local 23.0.0 Darwin Kernel Version 23.0.0: ...

AppleはDarwinをオープンソースで公開しています。あなたもopensource.apple.comでXNUソースを受け取ってビルドできます。

Machポート — すべての根源

Machマイクロカーネルの中核的抽象化はポート (port)です。MachポートはUnixのファイル記述子(file descriptor)に似た役割ですが、はるかに広範です。

  • プロセス間通信:メッセージをポートでやり取り
  • シグナル処理:UnixシグナルがMachポートメッセージに変換される
  • IOKitドライバ:ユーザー空間アプリがドライバとポートで通信
  • Bootstrap:ネームサービス(launchdが提供)もポートベース

なぜ重要か? macOSのセキュリティモデルとIPCがすべてポートの上に築かれています。例えばアプリサンドボックスは「このアプリはこの特定のポートだけ使える」で実装されます。iOSの厳格なアプリ隔離も根本的にMachポートベースです。

1
2
3
/* Machポートでメッセージを送る(極端に簡略化) */
mach_port_t target_port = ...;
mach_msg_send(&msg_header);

開発者が直接使うことはほぼありませんが、デバッガ(lldb)やXcode Instrumentsのようなツールの内部で動作しています。

Grand Central Dispatch (2009)

2009年のmacOS 10.6 Snow LeopardでAppleはGrand Central Dispatch (GCD、libdispatch) を導入しました。これはマルチコア時代に対するAppleの答えでした。

従来のスレッドモデルの問題

1
2
3
4
/* 伝統的なC/Unixスタイル */
pthread_t thread;
pthread_create(&thread, NULL, worker_function, arg);
pthread_join(thread, NULL);
  • 開発者がスレッド数、寿命、同期を直接管理
  • CPUコア数がわからなければ過剰または不足する
  • 同期プリミティブ使用にミスが多い

GCDの解決:スレッドではなくキューに作業を放る。

1
2
3
4
5
6
7
8
/* Swift */
DispatchQueue.global(qos: .userInitiated).async {
    /* ここの作業がバックグラウンドで実行される */
    let result = heavyComputation()
    DispatchQueue.main.async {
        updateUI(result)
    }
}

OSがCPUコア数、システム負荷などを考慮してスレッドを自動で生成/再利用します。開発者は「どの優先度で実行するか」だけを指定します(QoS:User Interactive、User Initiated、Utility、Background)。

GCDはオープンソースlibdispatchとして公開され、Swift on Linuxでも使われています。つまり、他の言語やプラットフォームでもGCDスタイルのプログラミングが可能です。

ゲーム開発の視点から:Unity Job SystemはGCDと思想が非常に似ています — 「スレッドではなく作業をスケジューラに任せる」。Part 13で詳しく扱います。

launchd — systemdより先に

2005年のmacOS 10.4 TigerでAppleはlaunchdを導入しました。これはUnixの伝統的なinitシステム(SysVinit、cron、xinetd、inetd、atdなど複数のデーモンが分散していた役割)を1つのプロセスに統合したものです。

launchd以前のUnix:

  • init (PID 1):起動時のシステム初期化
  • cron:定期的な作業
  • atd:一度だけの予約作業
  • inetd:ネットワーク要求時にデーモン起動
  • 各デーモンが別々に実行

launchdはこれらすべてを統合した万能デーモン管理者です:

  • PID 1として実行、システム全体のプロセス管理
  • XMLベースのplistファイルでサービス定義
  • ファイルアクセス、ネットワーク接続などのオンデマンド実行対応
  • 失敗時に自動再起動

歴史的意義:Linuxのsystemd(2010年Lennart Poettering)がlaunchdからインスピレーションを受けました。systemdが導入されたときLinuxコミュニティで「Unix哲学に反する」という批判が大きかったですが、すでにlaunchdが5年前に同じアプローチをしていて、macOSで何の問題もなく動いていました。

launchctlコマンドで管理:

1
2
3
4
5
6
7
8
# 実行中のサービス一覧
launchctl list

# 特定のサービス開始
launchctl load ~/Library/LaunchAgents/com.example.myservice.plist

# 停止
launchctl unload ~/Library/LaunchAgents/com.example.myservice.plist

Apple Silicon — P/Eコアの異種構造

2020年Appleは自社設計CPU M1 (Apple Silicon)をMacに導入しました。M1はARM64ベースですが一般的なARMサーバとは異なる独特な構造を持ちます。

Pコア (Performance) とEコア (Efficiency)

M1は同じARM ISAを実行する2種類のコアを持ちます:

  • Pコア “Firestorm”:高性能、高電力。ゲーム、コンパイル、レンダリングなどの重い作業
  • Eコア “Icestorm”:低性能、低電力。バックグラウンド作業、システムデーモン、バッテリ節約
スペックPコアEコア
クロック3.2 GHz2.0 GHz
L1キャッシュ192KB128KB
L2キャッシュ共有12MB共有4MB
電力〜15W〜1W
性能比〜100%〜25%
M1構成4個4個

macOSのQoSベーススケジューリング:前述のGCDのQoSクラスがここで再登場します。

  • User Interactive / User Initiated QoS → 主にPコア
  • Utility QoS → 状況次第
  • Background QoS → 主にEコア

開発者がDispatchQueue.global(qos: .userInitiated)と書くだけで、OSがどのコアで実行するか決めます。これがAppleの「開発者がハードウェアの詳細を知らなくていい」哲学です。

16KBページサイズ

Apple Siliconのもう1つの特異点はページサイズが16KBであることです。Linux/Windowsの標準は4KB

  • 長所:TLB (Translation Lookaside Buffer) のミスが減り、大容量メモリアプリの性能が向上
  • 短所:メモリアラインメント要求事項の変更。4KBページを前提とした古いアプリが動かないことがある

2020年Apple Silicon移行初期にHomebrew、Docker、一部のバイナリ互換性ツールが16KBページ問題で苦労しました。今はほとんど解決していますが、Unityネイティブプラグイン開発時にmprotect()呼び出しのようなものでページアラインメントに注意する必要があります。

Rosetta 2 — エミュレータではなく翻訳機

Apple Silicon移行の成功要因の1つはRosetta 2です。これはx86_64 Mach-OバイナリをARM64で実行します。驚くべきことにネイティブ性能の70〜80%が出ます。

Rosetta 2はJITエミュレータではありません。アプリをインストールするとき(または最初の実行時)にx86命令をARMにAOT(Ahead-of-Time)翻訳してファイルとして保存します。以降の実行はすでに翻訳されたARMバイナリを動かすことになるので速いのです。

決定的なトリック — ハードウェアTSOモード:この部分が最も興味深いです。

x86は強いメモリモデル (TSO、Total Store Order)を持ちます。あるCPUが書いた値が他のCPUに見える順序がプログラミング順序とほぼ同じです。

ARMは弱いメモリモデルを持ちます。CPUが性能のためにメモリ書き込み/読み出し順序を勝手に並べ替えられます。プログラマが明示的にメモリバリアを入れなければ順序は保証されません。

問題はx86用に書かれたプログラムがTSOを暗黙に仮定しているときに起こります。こういうプログラムを単純にARM命令に翻訳するとARMの並べ替えのせいでrace conditionが新しく発生します

Appleの解決:M1 CPUに「TSOモード」ハードウェアを入れました。Rosetta 2が翻訳したバイナリが実行されるとき、CPUに「このスレッドはTSOモードで動かせ」というフラグを立てます。するとARM CPUがx86と同じ強いメモリ順序で動作します。

💡 このテーマはPart 12(メモリモデルと原子演算)で再登場します。今は「Appleがハードウェアレベルで互換性トリックを使った」という点だけ覚えておけば十分です。

Rosetta 2の限界

  • AVX-512のような最新のx86拡張命令は翻訳されない
  • カーネル拡張(.kext)はRosettaで動かせない — OS自体はネイティブでなければならない
  • JITコンパイラ内蔵プログラム(Chrome V8エンジンなど)はRosetta + JITの二重翻訳になり遅くなる可能性

XNU内部構造

XNUカーネル内部 — Mach + BSD + I/O Kit ユーザー空間 (User Space) Cocoa / UIKit Swift / Objective-C POSIX アプリ (bash, ls) システムデーモン (launchd) syscall / Mach trap Kernel Space ↓ BSD Layer プロセスモデル (POSIX) ファイルシステム (APFS/HFS+) ネットワーク (BSD sockets) シグナル、権限 「私たちが見るUnixの顔」 Mach Microkernel Task(プロセス) Thread(スレッド) Mach Port (IPC) VM、スケジューラ 「CMU 1985〜91年の研究の産物」 I/O Kit(C++で書かれたドライバフレームワーク) GPU、USB、センサ、電源管理 Hardware (Apple Silicon / Intel)

Apple Silicon異種コア構造

Apple Silicon M1 — P/EコアとQoSマッピング M1 SoC (System on Chip) Pクラスタ (Firestorm × 4) P0 3.2 GHz P1 3.2 GHz P2 3.2 GHz P3 3.2 GHz Eクラスタ (Icestorm × 4) E0 2.0 GHz E1 2.0 GHz E2 2.0 GHz E3 2.0 GHz Unified Memory (16KBページ) CPU、GPU、Neural Engineが同じメモリプールを共有 macOS QoS → コアマッピング User Interactive / User Initiated → Pクラスタ Utility / Background → Eクラスタ

ちょっと、これは押さえておこう

「Rosetta 2はなぜ速いのか? エミュレータなのにネイティブ性能の70%は無茶苦茶では?」

3つの理由が重なっているからです。

  1. AOT翻訳(事前翻訳):エミュレータではありません。アプリをインストールするときや初回実行時にx86バイナリをARMに完全に翻訳してキャッシュします。以降はネイティブARMを実行するだけです。
  2. M1がそもそもx86よりはるかに速い:M1のシングルコア性能が同世代のIntel CPUより優れています。70%に落ちても絶対性能は悪くありません。
  3. ハードウェアTSOモード:x86のメモリモデルをARMに強制するためのソフトウェアエミュレーションは高価です。Appleはこれをハードウェアに入れてタダにしました。

限界:ハードウェアTSOモードはx86バイナリが実行されるときだけオンになります。ネイティブARMアプリは弱いメモリモデルをそのまま使います。


Part 6:3つのOSの長所短所表

これまでの内容を1枚の表にまとめます。各OSの強みと弱みを客観的に並べました。

開発者視点

領域LinuxWindowsmacOS
カーネルソースアクセス✅ 完全公開❌ 非公開🟡 Darwinのみ公開(GUI/Cocoa非公開)
CLI エコシステム✅ 最高 (bash、coreutilsネイティブ)🟡 PowerShell優秀、WSL必要✅ Unix標準ツール基本搭載
パッケージ管理✅ apt/dnf/pacman🟡 winget/choco(後発)🟡 Homebrew(非公式)
仮想化/コンテナ✅ Dockerネイティブ🟡 WSL 2 / Hyper-V🟡 Docker Desktop(VM経由)
言語対応✅ すべての言語✅ すべての言語(特に.NET)✅ すべての言語(Swiftが1級)
IDE🟡 VS Code、CLion✅ Visual Studio最高✅ Xcode、JetBrains
ドキュメント🟡 分散、manページ✅ MSDN体系的✅ Apple Developerドキュメント
コミュニティ✅ 巨大、開放的🟡 エンタープライズ中心🟡 Appleエコシステム中心

ゲーム開発視点

領域LinuxWindowsmacOS
主要グラフィックAPIVulkan、OpenGLDirectX 11/12、VulkanMetal(OpenGL/Vulkan対応終了中)
ゲームエンジン対応🟡 Unity/Unrealビルドターゲットのみ✅ 最高(エディタ含む)🟡 Unity/Unrealエディタ対応改善中
オーディオAPIALSA、PulseAudio、PipeWireXAudio2、WASAPICore Audio
デバッガ/プロファイラ🟡 GDB、Valgrind✅ Visual Studio✅ Instruments、Xcode
Steamゲームプレイ🟡 Proton(改善中)✅ ネイティブ🟡 制限的
VR/AR対応🟡 SteamVR✅ WMR、SteamVR🟡 Vision Proエコシステム

サーバ運用視点

領域LinuxWindowsmacOS
Webサーバシェア〜75%〜20%〜0%(サーバ用ではない)
コンテナネイティブ🟡 LCOW(LinuxコンテナをWSLで)
低資源運用✅ 最小数百MBで動作🟡 数GB必要🟡 サーバ用途はほぼない
ライセンス費用✅ 無料💰 有料 (Windows Server)🟡 Appleハードウェア必要

核心結論

  • 「最高のOS」は存在しない — 用途によって違います
  • サーバ/開発:Linuxが支配的
  • 企業/ゲームクライアント:Windowsが支配的
  • クリエイティブ作業/個人開発:macOSが強い
  • すべてのOSがお互いの強みを借りてきている
    • WindowsがWSLでLinux互換
    • macOSがHomebrewでLinuxツールエコシステムを活用
    • Linuxがデスクトップ UXの改善に投資

Part 7:セキュリティとサンドボックス — 簡潔に

OSごとにセキュリティモデルが違います。ゲーム開発視点で関連する部分だけ簡潔に。

macOS — 多層セキュリティ

SIP (System Integrity Protection):システムファイル保護。/System/binなどはrootでも修正不可。2015年のEl Capitanで導入。

Gatekeeper:署名されていないアプリの実行を遮断。「Appleで身元が確認されていない開発者」警告がこれ。

Notarization(公証):Appleにバイナリを提出してマルウェア検証を受けないとGatekeeper警告なしに実行不可。2019年義務化。

App Sandbox:Mac App Storeアプリは義務的にサンドボックス。一般アプリは選択的。ファイルシステム、ネットワーク、カメラなどをentitlementで明示。

Hardened Runtime:JIT、ライブラリ注入などを遮断する追加セキュリティ層。

開発者視点:Mac用商用アプリ配布時はApple Developerアカウント(99ドル/年)で署名 + 公証必須。ゲーム配布時に重要。

Windows — UACとDefender

UAC (User Account Control):管理者権限が必要な作業にユーザー確認。Vistaのときに導入され、悪評が立ちましたが今では必須のセキュリティモデル。

Windows Defender:基本内蔵アンチウイルス。Windows 10以降、サードパーティAVはほぼ不要なレベル。

Code Signing:Authenticode署名。EV証明書はSmartScreen警告なしに実行。ゲーム配布時に推奨。

AppContainer:UWPアプリ隔離。Mac App Sandboxと類似の概念ですが使用範囲が狭い。

Linux — 柔軟なツール群

User/Group権限:Unixの伝統。rwxビット、UID/GID。

Capabilities:rootの権限を分割して付与(CAP_NET_BIND_SERVICECAP_SYS_ADMINなど)。

SELinux / AppArmor:Mandatory Access Control。より細かいポリシー強制。

cgroups + namespaces:Dockerの基盤技術。プロセスグループに資源制限と隔離。

seccomp:システムコールフィルタリング。特定のシステムコールだけ許可するサンドボックス。

ゲーム開発時にAppImage、Flatpak、Snapのような配布形式は内部的にこれらの技術を使っています。


Part 8:ゲーム開発者の視点から

最後に、ゲーム開発者の立場から3つのOSの違いがどう現れるかを見ます。

プラットフォーム別ゲーム開発の考慮事項

1. Unityエディタ

  • Windows:フル機能、推奨プラットフォーム
  • macOS:対応良好、Apple Siliconネイティブビルド可能
  • Linux:限定的対応(公式Editorあり、プラグイン互換性は低下)

2. Unreal Engineエディタ

  • Windows:フル機能、基本対応
  • macOS:対応されるが一部機能制限(Vulkan対応など)
  • Linux:公式対応あり、エディタもビルド可能

3. グラフィックAPI選択

  • クロスプラットフォームが目標ならVulkan + DirectX 12抽象化
  • AppleプラットフォームターゲットならMetal検討(AppleがOpenGL/Vulkan対応を中断中)
  • Unity/Unrealのようなエンジンがこの抽象化を提供するが、ネイティブ最適化時は直接関与が必要

4. クラッシュハンドラ

  • Windows:SEH (Structured Exception Handling)SetUnhandledExceptionFilter
  • Linux/macOS:POSIXシグナルSIGSEGVSIGABRT)、signal()またはsigaction()
  • 2つのアプローチが違うため、クロスプラットフォームクラッシュレポータ(Sentry、Crashlytics)が複雑になる

5. ファイルパス

  • Windows:C:\Users\name\AppData\...、バックスラッシュ
  • macOS:/Users/name/Library/Application Support/...、スラッシュ
  • Linux:/home/name/.local/share/...(XDG標準)、スラッシュ
  • エンジンのApplication.persistentDataPathのような抽象化を使いつつ、直接扱うときは注意

6. スレッド優先度

  • Windows:SetThreadPriority、7段階(IDLE〜TIME_CRITICAL)
  • macOS:QoSクラス(4段階) + pthread優先度
  • Linux:nice値(-20〜19) + pthread SCHED_FIFO/RR
  • ゲームでオーディオスレッドのようなものに高い優先度を付ける必要があるときAPIが違う

クロスプラットフォームエンジンの抽象化

エンジンはOSの違いを隠すためのレイヤを持ちます。Unreal Engineの場合:

1
2
3
4
5
6
7
8
9
10
11
/* UE のプラットフォーム抽象化(概念的な例) */
#if PLATFORM_WINDOWS
#include "Windows/WindowsPlatformFile.h"
typedef FWindowsPlatformFile FPlatformFile;
#elif PLATFORM_MAC
#include "Apple/ApplePlatformFile.h"
typedef FApplePlatformFile FPlatformFile;
#elif PLATFORM_LINUX
#include "Unix/UnixPlatformFile.h"
typedef FUnixPlatformFile FPlatformFile;
#endif

そのためエンジン開発者(エンジンを修正するプログラマ)は3つのOSのAPIをすべて理解する必要があります。ゲームプログラマ(エンジンを消費する立場)はFPlatformFileのような抽象レイヤだけを見ればよいのです。

ツールチェーン互換性

ツールLinuxWindowsmacOS
主コンパイラgcc/clangMSVC/clang-clclang
標準ライブラリglibc/libstdc++/libc++MSVC STLlibc++
リンカld/lldlink.exe/lld-linkld64
デバッガgdb、lldbVisual Studio、WinDbglldb、Xcode
プロファイラperf、TracyVisual Studio Profiler、PIXInstruments
CI/CD可能性✅ 最高✅ GitHub Actions Windows Runner🟡 Mac Runnerは有料/制限

Appleの落とし穴:iOS/macOSアプリをビルドするにはXcodeが必要で、XcodeはmacOSでしか動きません。つまりAppleプラットフォームターゲットゲームを作るには必ずMacビルドマシンが必要です。CI/CDでMac Runnerが高価な理由です。

プラットフォーム別デバッグ体験比較

Windows (Visual Studio)

  • 最高レベルのIDE + デバッガ統合
  • Edit and Continue、条件付きブレークポイント、Data Breakpointすべてが滑らか
  • PIXでGPUプロファイリング

macOS (Xcode + Instruments)

  • Instrumentsは世界最高レベルのプロファイラの1つ(System Trace、Time Profiler、Allocations)
  • Apple SiliconのP/Eコアタイムラインを可視化してくれる
  • Metal Frame Debugger

Linux (gdb/lldb + Tracy)

  • コマンドラインツールが主。VS CodeがUXを大きく改善
  • Valgrind (Memcheck) は強力だが遅い
  • Tracy Profilerはクロスプラットフォーム最高オプションの1つ

まとめ

この回で扱った内容を1ページに要約します。

血統

  • Unix (1969) → BSD (1977) → NeXTSTEP (1989) → macOS (2001)
  • Unix → Minix → Linux (1991)
  • VMS (1977) + Dave Cutler → Windows NT (1993)

設計思想

  • Linux:開放性 + 性能
  • Windows:下位互換性
  • macOS:垂直統合 + 体験

カーネル構造

  • Linux:モノリシック
  • Windows NT:ハイブリッド
  • macOS XNU:Machマイクロカーネル + BSDレイヤ(二重構造)

バイナリ形式

  • Linux:ELF
  • Windows:PE(1981年のDOS互換MZヘッダを維持)
  • macOS:Mach-O(Universal Binaryで多重アーキテクチャ)

macOS特有のもの

  • XNU:理論はマイクロカーネル、実際はハイブリッド
  • Machポート:macOSのIPCとセキュリティのルーツ
  • Grand Central Dispatch (2009):「スレッドの代わりにキュー」抽象化
  • launchd (2005):systemdの5年前の原型
  • Apple Silicon:P/E異種コア + 16KBページ
  • Rosetta 2:AOT翻訳 + ハードウェアTSOモード

ゲーム開発時に覚えておく点

  • 実行バイナリ形式が違うため、マルチプラットフォームビルドは各OS別のビルド
  • クラッシュハンドラ、スレッド優先度、ファイルパスなど些細に見えるものもAPIが違う
  • エンジン抽象化レイヤを信じつつ、性能が重要な部分はプラットフォーム別最適化が必要
  • Appleプラットフォームターゲットなら必ずMacビルドマシンが必要

次の回からはこの地図をベースに具体的な理論に入ります。Part 8はプロセスとスレッド — PCB/TCB構造、fork()CreateProcess()の実際の違い、スレッドマッピングモデル、コンテキストスイッチコストまでをゲームエンジンの実行モデルと結びつけて見ていきます。


References

教科書

  • Silberschatz, Galvin, Gagne — Operating System Concepts, 10th ed., Wiley, 2018 — OS標準教科書、3章 (Processes)、4章 (Threads) 参照
  • Tanenbaum, Bos — Modern Operating Systems, 4th ed., Pearson, 2014 — microkernel vs monolithic論争の原点
  • Bovet, Cesati — Understanding the Linux Kernel, 3rd ed., O’Reilly, 2005 — Linuxカーネル内部
  • Russinovich, Solomon, Ionescu — Windows Internals, 7th ed., Microsoft Press, 2017 — NTカーネル詳細
  • Singh — Mac OS X Internals: A Systems Approach, Addison-Wesley, 2006 — XNU、Mach、BSDレイヤ
  • Levin — *OS Internals: Volume I - User ModeVolume II - Kernel Mode, Technologeeks, 2019 — macOS/iOS内部の最も詳細な現代の著述
  • Gregory — Game Engine Architecture, 3rd ed., CRC Press, 2018 — ゲームエンジンでのOS活用

論文 / 研究資料

  • Accetta, Baron, Bolosky, Golub, Rashid, Tevanian, Young — “Mach: A New Kernel Foundation for UNIX Development”, USENIX Summer 1986 — Machの最初の説明論文
  • Young, Tevanian, Rashid, Golub, Eppinger, Chew, Bolosky, Black, Baron — “The Duality of Memory and Communication in the Implementation of a Multiprocessor Operating System”, SOSP 1987
  • Rashid, Baron, Forin, Golub, Jones, Julin, Orr, Sanzi — “Mach: A Foundation for Open Systems”, Workshop on Workstation Operating Systems, 1989
  • Bershad, Anderson, Lazowska, Levy — “Lightweight Remote Procedure Call”, SOSP 1989 — microkernel IPC最適化
  • Anderson, Bershad, Lazowska, Levy — “Scheduler Activations: Effective Kernel Support for the User-Level Management of Parallelism”, SOSP 1991 — M:Nスレッドモデル

公式ドキュメント / ソース

ブログ / 記事

  • Raymond Chen — The Old New Thing — Windows下位互換性逸話(SimCity事例含む)
  • Howard Oakley — The Eclectic Light Company — macOS内部動作解説
  • Hector Martin (marcan) — Apple Silicon逆解析 — Asahi Linuxプロジェクト
  • Dougall Johnson — “M1 Memory and Performance” シリーズ — Apple Siliconハードウェア分析
  • Linus Torvalds — comp.os.minix “Hello everybody” post (1991-08-25)
  • Linus vs. Tanenbaum debate (1992) — microkernel論争アーカイブ

ツール

  • filereadelfobjdump (Linux) — ELF解析
  • dumpbinPEview (Windows) — PE解析
  • otoolnmlipo (macOS) — Mach-O解析
  • launchctlpstop — 3つのOS共通の観察ツール
  • Instruments (macOS) — Apple公式プロファイラ

画像出典

  • Ken Thompson & Dennis Ritchie (1973) — Jargon File, Public Domain — Wikimedia Commons
  • Linus Torvalds at LinuxCon Europe 2014 — 写真 Krd, CC BY-SA 4.0 — Wikimedia Commons
  • NeXTcube (1990) at Computer History Museum — 写真 Michael Hicks, CC BY 2.0 — Wikimedia Commons
この記事は著者の CC BY 4.0 ライセンスの下で提供されています。