速度・容量・コストの異なる記憶装置を階層的に組み合わせる構成
メモリ階層(memory hierarchy)とは、速度・容量・価格の異なる記憶装置を、ピラミッドのように何段階かに重ねて組み合わせる構成のことです。記憶装置(メモリ=データを覚えておく部品)には「速いが高価で少ししか置けないもの」と「遅いが安くて大量に置けるもの」があり、どちらか一方だけでは都合が悪いため、両方を組み合わせて使います。
身近な例で考えると、机の上・引き出し・倉庫の関係に似ています。今すぐ使う書類は手元の机の上(=速いがすぐ散らかる狭い場所)に置き、ときどき使うものは引き出しに、めったに使わないものは倉庫(=広いが取りに行くのが遅い)にしまいます。全部を机の上に置くのは無理なので、よく使うものだけを手元に集めるわけです。
上のピラミッド図で、頂点に近いレジスタはCPU(=中央処理装置。計算を行う部品)のすぐそばにある最速の記憶で、底辺の補助記憶はSSDやHDDといった大容量のストレージです。CPUは必要なデータを上の層から順に探し、なければ下の層から運んでくる、という流れで動きます。
メモリ階層は大きく4つの層に分かれます。上の層ほどCPUに近く、下の層ほど遠くなります。
| 階層 | 実体 | 速度 | 容量 |
|---|---|---|---|
| レジスタ | CPU内部の記憶素子 | 最速(1ns未満) | 数百バイト |
| キャッシュ | SRAM(L1/L2/L3) | 高速(数ns) | 数MB |
| 主記憶 | DRAM(メインメモリ) | 中速(数十ns) | 数GB |
| 補助記憶 | SSD / HDD | 低速(μs〜ms) | 数百GB〜数TB |
それぞれの層の役割を整理します。
・レジスタ:CPUが今まさに計算で使っている値を入れておく、もっとも速い小さな記憶
・キャッシュメモリ:よく使うデータをCPUの近くにコピーしておき、主記憶へのアクセスを減らす
・主記憶(メインメモリ):実行中のプログラムやデータを置く作業場。電源を切ると消える
・補助記憶(ストレージ):電源を切っても消えない大容量の保管庫。プログラムやファイルを長期保存する
数値の桁感をつかむと理解が深まります。レジスタの速度を「1秒」とたとえると、主記憶は「数十秒」、補助記憶(HDD)は「数日〜数ヶ月」に相当するほど差があります。だからこそ、遅い層へのアクセスをいかに減らすかが性能の鍵になります。
トレードオフ(trade-off=あちらを立てればこちらが立たない関係)とは、ここでは「速さ」と「容量・安さ」が同時には手に入らないという性質を指します。速い記憶は構造が複雑で高価なため大量には作れず、安くて大量に作れる記憶は遅い、という関係が常にあります。
上の層ほど次のような性質を持ちます。
・速度:上ほど速い(CPUに近いほど待ち時間が短い)
・容量:上ほど小さい(高価なので少ししか積めない)
・1バイトあたりのコスト:上ほど高い(同じ容量なら下の層のほうがずっと安い)
もし全部を最速のレジスタで作れば理想的ですが、価格が天文学的になり現実的ではありません。逆に全部を安い補助記憶にすると、容量は十分でも遅すぎて使い物になりません。そこで「よく使うデータほど上の層に置く」ことで、見かけ上「速くて大容量」という良いとこ取りを実現します。これが階層構造を作る最大の目的です。この仕組みを支えるのが、次に学ぶキャッシュメモリです。
キャッシュメモリが効果を発揮できるのは、プログラムが同じデータや近いデータを繰り返し使う傾向があるからです。この傾向を局所性の原理(principle of locality)と呼びます。局所性には2種類あります。
・時間的局所性:一度使ったデータは近い将来また使われやすい(例:ループ内で毎回参照する変数)
・空間的局所性:あるアドレスのデータを使ったら、その周辺のアドレスも近くに使われやすい(例:配列を順番に読む処理)
なぜキャッシュはデータをまとめて取ってくるのか。キャッシュは主記憶から1バイトだけでなく、その周辺ごとまとめて(=キャッシュラインという単位で)コピーします。空間的局所性があるので、周辺データもすぐ使われる可能性が高く、まとめて持ってきておくと次のアクセスが速くなるのです。
身近な例で言えば、料理のとき調味料を一通りコンロ脇に並べておくようなものです。1回使った塩をしまわずそのまま置いておけば次にすぐ取れる(時間的局所性)。塩・砂糖・醤油をまとめて手元に持ってくれば、どれかを使うたびに棚まで取りに行かなくて済む(空間的局所性)。この2つの性質がある限り、キャッシュは高い効率で動き続けます。
CPUがデータを読むとき、必ず速い層(上)から順番に探します。
・まずキャッシュにあれば即座に返す → これをキャッシュヒットと言います
・キャッシュになければ主記憶から読み、キャッシュにもコピーする → キャッシュミス(待ち時間が増える)
・主記憶にもなければ補助記憶から読み込む → さらに大きな待ち時間が発生
速度差はどのくらいか?レジスタのアクセスを「1秒」に例えると、キャッシュは「5〜30秒」、主記憶は「数分」、HDD(古いハードディスク)は「数日〜数週間」に相当するほどの差があります。だからキャッシュミスが続くと、CPUが強くなっても体感速度が上がらない、という現象が起きます。
キャッシュヒット率(hit rate)が高いほどプログラムは速く動きます。ヒット率は「キャッシュで見つかった回数 ÷ アクセスの総回数」で求められます。たとえばヒット率 95%・ヒット時1クロック・ミス時100クロックの場合の実効アクセス時間(実際の平均アクセス時間)は次のように計算します。
実効アクセス時間 = 0.95 × 1 + 0.05 × 100 = 0.95 + 5 = 5.95 クロック
ヒット率が高いほど実効アクセス時間はヒット時のアクセス時間に近づき、コンピュータ全体が速く動きます。