ストレージ階層とキャッシュ階層の統合設計
なぜ速いメモリほど小さいのか、その理由が腑に落ちます。レジスタからディスクまでの記憶階層を、各層のレイテンシ・容量・コストと、OSがどの層をどう管理するかまで一気通貫で俯瞰します。
- 1.記憶階層は、上位ほど高速・小容量・高コスト、下位ほど低速・大容量・低コスト。各層の容量とレイテンシはおおむね桁で変わり、上位の小さな層で下位の大きな層を覆い隠す(キャッシュする)のが基本原理。
- 2.なぜ機能するかは局所性(時間的・空間的)に尽きる。直近に触れたデータと、その近傍が再び使われる確率が高いので、小さな高速層に置くだけでヒット率が跳ね上がり、実効レイテンシが上位層に近づく。
- 3.層の管理主体は分かれる。CPUキャッシュとTLBはハードウェアが自動管理、ページキャッシュ・スワップ・先読みはOSが管理、レジスタ割り当てはコンパイラが担う。OSが触れるのは主記憶から下の境界。
記憶階層という発想:速さと容量はトレードオフ
理想のメモリは「無限に大きく、無限に速く、無料」ですが、物理と経済がそれを許しません。SRAM は速いが高価で集積度が低く、DRAM は安いが遅く、フラッシュや磁気ディスクはさらに安く大容量だが桁違いに遅い。この制約への工学的回答が 記憶階層(memory hierarchy) です。
発想は単純です。小さくて速い層に、大きくて遅い層の「よく使う一部」を写しておく。要求の大半が上位層で満たされれば、下位層の遅さは平均すると見えなくなります。各層は下位層の キャッシュ として働き、上に行くほど速く小さく高価、下に行くほど遅く大きく安い、というピラミッドが立ち上がります。
L1 は L2 のキャッシュ、L2 はメモリのキャッシュ、メモリはディスクのキャッシュ……と捉えると、全層が同じ原理の入れ子だと分かります。違うのは管理主体(ハードウェアかOSか)と、ヒット/ミス時のコストの桁だけです。
各層のレイテンシ・容量・コスト
代表的な層を、上位から並べます。数値はアーキテクチャ世代で動きますが、桁(オーダー)の感覚が要点です。
| 層 | 代表容量 | アクセスレイテンシの目安 | 管理主体 |
|---|---|---|---|
| レジスタ | 数百バイト | 0サイクル(命令と同時) | コンパイラ |
| L1キャッシュ | 数十KB | 約1ns(数サイクル) | ハードウェア |
| L2キャッシュ | 数百KB〜数MB | 数ns(十数サイクル) | ハードウェア |
| L3キャッシュ(共有) | 数MB〜数十MB | 約10〜20ns | ハードウェア |
| 主記憶(DRAM) | 数GB〜数百GB | 約60〜100ns | OS(割り当て・ページング) |
| NVMe SSD | 数百GB〜数TB | 約10〜100µs | OS(ファイル/ブロック層) |
| 磁気ディスク(HDD) | 数TB | 約5〜10ms | OS(ファイル/ブロック層) |
レジスタからメモリまでで実効レイテンシはおよそ100倍、メモリから SSD でさらに約1000倍、SSD から HDD でさらに約100倍開きます。メモリと SSD の間が最大の崖 で、ここがOSの設計上もっとも神経を使う境界です。コストは逆順で、容量あたり単価は上位ほど高く、下位ほど安くなります。
ここに挙げた ns/µs/ms は世代やベンダで容易に倍半分します。暗記すべきは「L1≒1ns、メモリ≒100ns、SSD≒数十µs、HDD≒数ms」という桁の階段です。設計判断(どこにキャッシュを置くか、何回I/Oを許すか)は絶対値ではなくこの桁差で決まります。
なぜ機能するのか:局所性の原理
小さな高速層で大きな低速層を覆い隠せるのは、プログラムのアクセスが一様ランダムではなく 局所性(locality of reference) を持つからです。これが階層全体の前提です。
- 時間的局所性(temporal locality):一度参照したアドレスは、近い将来また参照されやすい。ループ変数、ホットな関数、頻繁に触る構造体など。→ 直近のデータを上位層に留めておけば再ヒットする。
- 空間的局所性(spatial locality):あるアドレスを参照したら、その近傍も参照されやすい。配列の走査、構造体のフィールド連続アクセス、命令の逐次実行など。→ 1個要求されたら近傍をまとめて上位層へ運ぶと、後続が先回りでヒットする。
空間的局所性ゆえに、各層は単体のバイトではなく ブロック単位 でデータを動かします。CPU キャッシュは キャッシュライン(典型 64 バイト)、OS のページングは ページ(典型 4KB)、ストレージは セクタ/ブロック(4KB など)単位です。粒度は層ごとに違いますが、「近傍をまとめて運んで固定コストを償却する」狙いは共通です。
実効レイテンシ = ヒット率 × ヒット時間 + (1 − ヒット率) × ミスペナルティ
例: ヒット時間 1ns、ミスペナルティ 100ns の層
ヒット率 99% → 0.99×1 + 0.01×100 = 1.99ns
ヒット率 90% → 0.90×1 + 0.10×100 = 10.9ns
この式が階層設計の核心です。ミスペナルティ(下位層への往復)が大きくても、ヒット率が十分高ければ実効レイテンシは上位層のヒット時間に近づきます。逆にヒット率が数%落ちるだけで実効レイテンシは跳ね上がるため、各層は「いかにヒット率を保つか」に最適化されます。CPU キャッシュの詳細は メモリ階層とキャッシュコヒーレンシ(MESIプロトコル) を参照してください。
どの層を誰が管理するか:境界線
記憶階層でしばしば混乱するのが「この層はOSが管理しているのか」という点です。実は管理主体は層によって明確に分かれます。
| 層の範囲 | 管理主体 | OSの関与 | ミス処理の主体 |
|---|---|---|---|
| レジスタ | コンパイラ(レジスタ割り当て) | なし | —(あふれはスタックへスピル) |
| L1/L2/L3キャッシュ | ハードウェア(自動) | 原則なし(プリフェッチ命令等で間接的にのみ) | ハードウェアがラインを充填 |
| TLB | ハードウェア(自動充填)/OS(ページテーブル提供) | ページテーブルを用意し、必要ならフラッシュ | ハードまたはOSのフォルトハンドラ |
| 主記憶(物理フレーム) | OS | 割り当て・回収・ページング全般 | OS(ページフォルトハンドラ) |
| ストレージ | OS(ファイル/ブロック層)+デバイス | ページキャッシュ・I/Oスケジューリング | OS+デバイスファームウェア |
ここから読み取れる原則は明快です。OSが能動的に「どの層に何を置くか」を判断するのは、主記憶とその下から。CPU キャッシュとレジスタは、ハードウェアとコンパイラがプログラムの実行から自動的に管理し、OS はせいぜいヒント(プリフェッチ、madvise など)を出せるだけです。一方、主記憶より下では、どのページをメモリに載せ、どれをストレージへ退避し、いつ書き戻すかをOSがアルゴリズムで明示的に決めます。
キャッシュ層(L1〜L3、TLB、ページキャッシュ)はアプリから見て透過的で、ヒット/ミスは性能差として現れるだけで意味論は変わりません。一方、スワップやファイルI/Oは意味論にも影響し得る(fsyncで永続化、メジャーフォルトで停止など)。設計時は「この層はただ速くするだけか、保証や停止を伴うか」を区別すると整理できます。
OSが管理する層の具体:キャッシュ・ページング・スワップ
OS が主記憶以下を「上位(速い側)のキャッシュ」として運用する具体的な機構は、大きく3つに整理できます。役割と方向が異なるので分けて押さえます。
- ページキャッシュ(ファイル⇄メモリ):ストレージ上のファイルの中身を、ページ単位でメモリに保持する。
readの多くはメモリヒットで済み、writeはまずキャッシュに溜めて即返る(ライトバック)。メモリをストレージのキャッシュとして使う機構です。詳細は ページキャッシュとライトバックの仕組み を参照してください。 - デマンドページング+先読み(メモリへの充填):プログラムのページは、実際に触れられた瞬間にページフォルト経由でロードされる。空間的局所性を見越して近傍ページを 先読み(readahead) し、後続アクセスを先回りでヒットさせます。これは記憶階層の「ミス時にブロック単位で運ぶ」をOSレベルで実装したものです。
- スワップ(メモリ⇄ストレージ、退避方向):メモリが逼迫したとき、当面使われない匿名ページをストレージへ退避してフレームを空ける。メモリ容量を仮想的に拡張し、ストレージを最下層として階層に組み込みます。詳細は スワッピングとページング機構の内部 を参照してください。
OSから見た層の充填と退避(主記憶を中心に):
ストレージ(ファイル/スワップ)
│ read/ページフォルト+先読み(↑充填)
│ ライトバック/スワップアウト(↓退避)
▼
主記憶(ページキャッシュ+匿名ページ)
│ ロード/ストア(ハードウェアが自動)
▼
L1/L2/L3 → レジスタ(OSは関与しない領域)
つまりOSは、主記憶という1つの層を「上のCPUキャッシュへの供給元」かつ「下のストレージのキャッシュ」として両面運用しています。上向きにはハードウェアに任せ、下向きには自らアルゴリズム(回収・先読み・書き戻し)で制御する、という非対称が要点です。
ヒット率を守る共通アルゴリズム:置換と局所性管理
どの層も容量が有限なので、満杯になれば「何を追い出すか」を決める 置換(replacement) が必要です。ここでも局所性が指針になり、層をまたいで似たアルゴリズムが現れます。
- CPU キャッシュ:ハードウェアが擬似 LRU(pseudo-LRU)でラインを追い出す。厳密 LRU は実装コストが高いため近似する。
- TLB:ハードウェアが LRU 近似で古いエントリを置換。OS は文脈切り替えやページ変更時にフラッシュで関与する。
- ページキャッシュ/匿名ページ:OS が active/inactive の二段 LRU に anon/file 別管理を重ねた近似 LRU で回収候補を選ぶ。
このように、「最近使っていないものから追い出す(時間的局所性の活用)」が全層を貫く共通戦略です。置換アルゴリズムが下手だと、必要なデータを追い出した直後に再要求される(リファレンスのスラッシング)が起き、ヒット率が崩壊して実効レイテンシが下位層に張り付きます。
記憶階層は「上位層が高い確率でヒットする」という前提でのみ速さを発揮します。ワーキングセット(一定時間に実際に触るページ集合)が上位層の容量を超えると、置換が暴走してミスばかりになり、実効レイテンシは最下層に支配されます。メモリでこれが起きるのがスラッシング、CPU キャッシュで起きるのがキャッシュミスの多発です。容量設計は常にワーキングセットを基準に行います。
なお、マルチソケット環境では「主記憶」も一様ではなく、自ノードのメモリは速く、他ノードのメモリは遅い、という階層がさらに加わります。これは NUMAとメモリアクセス局所性 の領域で、記憶階層の「近いほど速い」がソケット間距離にも当てはまる例です。
(1)階層は上位ほど高速・小容量・高コストで、各層が下位層のキャッシュとして働くこと。(2)機能の根拠は時間的・空間的局所性であり、実効レイテンシ=ヒット率×ヒット時間+ミス率×ミスペナルティで決まること。(3)管理主体の境界:レジスタはコンパイラ、CPUキャッシュ/TLBはハードウェア、主記憶以下はOS。(4)OSの三機構(ページキャッシュ=メモリをストレージのキャッシュに、デマンドページング+先読み=充填、スワップ=退避)の役割と方向。この4点が頻出です。
まとめ
- 記憶階層 は、上位ほど高速・小容量・高コスト、下位ほど低速・大容量・低コストという物理と経済の制約への回答。各層が下位層のキャッシュとして働き、レイテンシはレジスタ≒1サイクル、L1≒1ns、メモリ≒100ns、SSD≒数十µs、HDD≒数ms と桁で階段状に開く。
- これが機能するのは 局所性 ゆえ。時間的局所性で再ヒットし、空間的局所性ゆえに各層はブロック(ライン/ページ/セクタ)単位で運ぶ。実効レイテンシはヒット率に支配される。
- 管理主体は層で分かれる。レジスタはコンパイラ、L1〜L3とTLBはハードウェア、主記憶から下はOS。OSが能動的に層配置を決めるのは主記憶以下。
- OSの管理は ページキャッシュ(メモリをストレージのキャッシュに)/デマンドページング+先読み(充填)/スワップ(退避) の三機構に整理でき、いずれも局所性と近似LRUでヒット率を守る。
CPU キャッシュ側の詳細は メモリ階層とキャッシュコヒーレンシ(MESIプロトコル)、OSが管理する下位層は ページキャッシュとライトバックの仕組み と スワッピングとページング機構の内部、ソケット間に広がる階層は NUMAとメモリアクセス局所性 を合わせて読むと、記憶階層の全体像が立体的に繋がります。
OS Article
ストレージ階層とキャッシュ階層の統合設計を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
記憶階層
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
なぜ機能するかは局所性(時間的・空間的)に尽きる。直近に触れたデータと、その近傍が再び使われる確率が高いので、小さな高速層に置くだけでヒット率が跳ね上がり、実効レイテンシが上位層に近づく。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「記憶階層 / キャッシュ」に近いか確認する。
- 強みである「記憶階層は、上位ほど高速・小容量・高コスト、下位ほど低速・大容量・低コスト。各層の容量とレイテンシはおおむね桁で変わり、上位の小さな層で下位の大きな層を覆い隠す(キャッシュする)のが基本原理。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。