コンピュータを購入したことがある方なら、「キャッシュ」という言葉を聞いたことがあるでしょう。また、このテーマに関して善意の友人から「その Celeron チップは買わないでください。キャッシュが入っていないのです!」といったアドバイスを受けたことがあるかもしれません。では、そもそもキャッシュとは何でしょうか?
キャッシュは、あらゆるコンピューターにさまざまな形で現れる重要なコンピューター サイエンス プロセスであることがわかりました。最近のコンピューターには L1 キャッシュと L2 キャッシュの両方が搭載されており、多くのコンピューターには L3 キャッシュも搭載されています。メモリ キャッシュ、ページ キャッシュ、さらにはハードウェアとソフトウェアのディスク キャッシュもあります。仮想メモリもキャッシュの一種です。
この記事では、キャッシュとは何かを説明し、キャッシュがどのように機能するかを探って、キャッシュがなぜそれほど重要なのかを理解できるようにします。
簡単な例: キャッシュ前
キャッシュは、コンピュータのメモリ サブシステムに基づくテクノロジです。キャッシュの主な目的は、コンピュータの価格を低く抑えながらコンピュータを高速化することです。キャッシュを使用すると、コンピュータのタスクをより迅速に実行できるようになります。
キャッシュ システムの背後にある基本的な考え方を理解するために、ライブラリアンを使用してキャッシュの概念を示す非常に単純な例から始めましょう。机の後ろにいる図書館員を想像してみましょう。彼はあなたが求める本をあなたに与えるためにそこにいます。話を簡単にするために、自分で本を手に入れることができないとしましょう。読みたい本があれば図書館司書に尋ねる必要があり、司書は倉庫にある一連の書庫から本を取ってきてくれます。 (ワシントン DC の米国議会図書館はこのように設置されています。)
まず、キャッシュのないライブラリアンから始めましょう。最初のお客さんが到着。彼は『白鯨』という本を求めます。司書は倉庫に入り、本を受け取り、カウンターに戻り、本を顧客に渡します。その後、顧客が本を返しに戻ってきます。司書は本を受け取り、倉庫に返します。その後、彼はカウンターに戻り、別の顧客を待ちます。
さて、次の顧客が白鯨を求めたとします。その後、司書は保管庫に戻って、最近扱った本を取り出して顧客に渡さなければなりません。このモデルでは、図書館員は、頻繁にリクエストされる非常に人気のある本であっても、すべての本を取り出すために往復する必要があります。どうすれば図書館員のパフォーマンスを向上させることができるでしょうか?私たちは彼にキャッシュを置きました!
簡単な例: キャッシュされたバージョン
図書館員に 10 冊の本を収納できるバックパックを与えましょう (コンピュータ用語で言うと、図書館員は 10 冊の書籍のブラウザ キャッシュを持っています)。このバックパックには、クライアントが返してくる本を最大 10 冊まで入れます。前の例を使用してみましょう。ただし、今度は新しく改良されたキャッシュ ライブラリアンを使用します。
一日が始まります。図書館司書のバックパックは空です。最初のクライアントが到着し、白鯨を求めてきました。ここには魔法はありません。司書は本を取りに倉庫に行かなければなりません。彼はそれをクライアントに渡します。その後、顧客は戻ってきて、その本を司書に返します。司書は本を返すために倉庫に戻る代わりに、本をバックパックに入れてそこに立ちます(最初にバッグがいっぱいかどうかを確認します。これについては後で詳しく説明します)。
別の顧客が到着し、白鯨を要求します。図書館員は倉庫に行く前に、この本が自分のバックパック(または一時保管庫)の中にあるかどうかを確認します。彼はそれを見つけました!それをキャッシュヒットといいます。彼がしなければならないことは、バックパックから本を取り出してクライアントに渡すことだけです。倉庫に入る必要がないため、顧客へのサービスがより効率的に行われます。
キャッシュミスが発生した場合
クライアントがキャッシュ (バックパック) にないタイトルを要求した場合はどうなるでしょうか?この場合、図書館員は最初にバックパック内の本を探すのに時間がかかるため、キャッシュがある場合はキャッシュがない場合よりも効率が悪くなります。キャッシュ設計の課題の 1 つは、キャッシュ検索の影響を最小限に抑えることですが、最新のハードウェアではこの時間遅延が実質的にゼロに短縮されています。
単純な図書館員の例でも、キャッシュを検索する待ち時間 (待機時間) は、保管庫に戻る時間に比べて非常に小さいため、重要ではありません。キャッシュは小さく (10 冊)、キャッシュミスに気づくまでにかかる時間は、倉庫に行くのにかかる時間のほんの一部にすぎません。
キャッシュ: データを一時的に保存する場所
この例から、キャッシュに関するいくつかの重要な事実がわかります。
- キャッシュ テクノロジは、高速だが小型のメモリ タイプを使用して、低速だが大容量のメモリ タイプを高速化することです。すべてのオペレーティング システムと Web サーバーで動作します。
- キャッシュを使用する場合は、キャッシュをチェックしてそこに項目があるかどうかを確認する必要があります。存在する場合、それはキャッシュ ヒットと呼ばれます。そうでない場合はキャッシュミスと呼ばれ、コンピュータはより大きくて遅いメモリ領域からのラウンドトリップを待たなければなりません。
- キャッシュには、より大きな記憶領域よりもはるかに小さい最大サイズがあります。
- 複数のキャッシュ層を持つことが可能です。図書館員の例では、小型だが高速なメモリ タイプはバックパックであり、物置はより大型で低速なメモリ タイプを表します。これは 1 レベルのキャッシュです。カウンターの後ろに 100 冊の本を保管できる棚で構成されるキャッシュの別の層がある可能性があります。司書はバックパック、次に棚、そして物置をチェックできます。これは 2 レベルのキャッシュになります。
キャッシュメモリのレベル
コンピューターは、時間を非常に小さな増分で測定する機械です。マイクロプロセッサがランダム アクセス メモリ ( RAM ) にアクセスする場合、約 60 ナノ秒 (1 秒の 600 億分の 1) でアクセスが行われます。これはかなり高速ですが、一般的なマイクロプロセッサよりもはるかに遅いです。マイクロプロセッサのサイクル時間はわずか 2 ナノ秒なので、マイクロプロセッサにとって 60 ナノ秒は永遠のように思えます。
小さいながらも非常に高速 (約 30 ナノ秒) の特別なメモリ バンクをマザーボードに構築したらどうなるでしょうか?これはすでにメインメモリへのアクセスよりも 2 倍高速です。それはレベル 2 キャッシュまたは L2 キャッシュと呼ばれます。さらに小型で高速なメモリ システムをマイクロプロセッサのチップに直接構築したらどうなるでしょうか?こうすることで、このメモリはメモリ バスの速度ではなく、マイクロプロセッサの速度でアクセスされます。これは L1 キャッシュで、233 メガヘルツ (MHz) の Pentium では、L2 キャッシュよりも 3.5 倍高速で、メイン メモリへのアクセスよりも 2 倍高速です。
一部のマイクロプロセッサには、チップに直接 2 レベルのキャッシュが組み込まれています。この場合、マザーボード キャッシュ (マイクロプロセッサとメイン システム メモリの間に存在するキャッシュ) はレベル 3、つまり になります。
コンピューターには多数のサブシステムがあり、それらの多くの間にキャッシュを配置してパフォーマンスを向上させることができます。ここに例を示します。私たちはマイクロプロセッサ(コンピュータの中で最も速いもの)を持っています。次に、メイン メモリをキャッシュする L1 キャッシュと、ハードディスクやCD-ROMなどのさらに遅い周辺機器のキャッシュとして使用できる (そして頻繁に使用される) メイン メモリをキャッシュする L2 キャッシュがあります。ハードディスクは、さらに遅いメディア、つまりインターネット接続をキャッシュするためにも使用されます。
ブラウザキャッシュ: 頻繁にアクセスされるデータ用
インターネット接続は、コンピュータ内で最も遅いリンクです。そのため、Web ブラウザ (Safari、Google Chrome、およびすべて) はハードディスクを使用してHTML ページを保存し、ディスク上の特別なフォルダに HTML ページを保存します。初めて HTML ページを要求すると、ブラウザーがそのページをレンダリングし、そのコピーもディスクに保存されます。
次回このページへのアクセスをリクエストすると、ブラウザはインターネット上のファイルの日付がキャッシュされた日付よりも新しいかどうかを確認します。日付が同じ場合、ブラウザはインターネットからダウンロードする代わりに、ハードディスク上の日付を使用します。この場合、小さくても高速なメモリ システムはハードディスクであり、大きくて遅いメモリ システムはインターネットです。
キャッシュは周辺機器上に直接構築することもできます。最新のハードディスクには、約 512キロバイトの高速メモリがハードディスクに配線されています。コンピューターはこのメモリを直接使用せず、ハードディスク コントローラーが使用します。コンピュータにとって、これらのメモリ チップはディスクそのものです。
コンピュータがハードディスクにデータを要求すると、ハードディスク コントローラはハードディスクの機械部品を動かす前にこのメモリをチェックインします (これはメモリに比べて非常に遅いです)。要求されたデータがキャッシュ内で見つかった場合は、ディスク自体上のデータに実際にアクセスすることなく、キャッシュに保存されているデータを返すため、時間を大幅に節約できます。
キャッシュされたデータのサブシステム
ここで試してみましょう。コンピュータはフロッピー ドライブをメイン メモリにキャッシュしており、実際にそれが起こっているのを確認できます。フロッピーから大きなファイルにアクセスします。たとえば、テキスト エディタで 300 キロバイトのテキスト ファイルを開きます。初めて、フロッピーのライトが点灯するのがわかり、待ちます。フロッピー ディスクは非常に遅いため、ファイルをロードするのに 20 秒かかります。
次に、エディタを閉じて、同じファイルを再度開きます。 2 回目は (30 分待ったり、2 回の試行の間に大量のディスク アクセスを行わないでください)、ライトが点灯することはなく、待ちません。オペレーティング システムはフロッピー ディスクのメモリ キャッシュをチェックインし、探していたものを見つけました。
そのため、20 秒待つ代わりに、最初に試したときよりもはるかに速くメモリ サブシステムでデータが見つかりました (フロッピー ディスクへの 1 回のアクセスには 120 ミリ秒かかりますが、メイン メモリへの 1 回のアクセスには約 60 ナノ秒かかります。これははるかに高速です) )。ハードディスクでも同じテストを実行することもできますが、フロッピー ドライブでは非常に遅いため、テストの結果がより顕著になります。
全体像を把握するために、通常のキャッシュ システムのリストを次に示します。
- L1 キャッシュ– マイクロプロセッサの最大速度でのキャッシュ メモリ アクセス (10 ナノ秒、サイズは 4 キロバイトから 16 キロバイト)
- L2 キャッシュ– SRAMタイプのキャッシュ メモリ アクセス (約 20 ~ 30 ナノ秒、サイズは 128 キロバイト ~ 512 キロバイト)
- メイン メモリ– RAMタイプのメモリ アクセス (約 60 ナノ秒、サイズは 32メガバイトから 128 メガバイト)
- ハードディスク– 機械式、低速 (約 12 ミリ秒、サイズは 1 GB ~ 10 GB)
- インターネット– 非常に遅い (1 秒から 3 日、サイズは無制限)
ご覧のとおり、L1 キャッシュは L2 キャッシュ データをキャッシュし、L2 キャッシュ データはディスク サブシステムのキャッシュに使用できるメイン メモリをキャッシュします。
データのキャッシュが重要な理由
この時点でよく聞かれる質問の 1 つは、「キャッシュを必要としないように、コンピュータのすべてのメモリを L1 キャッシュと同じ速度で実行できないのはなぜですか?」というものです。それはうまくいきますが、信じられないほど高価になります。キャッシュの背後にある考え方は、少量の高価なメモリを使用して、低速で安価な大量のメモリを高速化することです。
コンピューターを設計する際の目標は、マイクロプロセッサーをできるだけ安価にフルスピードで実行できるようにすることです。 500 MHz のチップは 1 秒間に 5 億サイクル (2 ナノ秒ごとに 1 サイクル) を実行します。 L1 および L2 キャッシュがないと、メイン メモリへのアクセスに 60 ナノ秒かかり、メモリにアクセスする約 30 サイクルの無駄になります。
考えてみると、このような比較的少量のメモリで、はるかに大量のメモリを最大限に活用できるというのは、ある意味信じられないことです。 64 メガバイトの RAM をキャッシュする 256 キロバイトの L2 キャッシュについて考えてみましょう。この場合、256,000 バイトで 64,000,000 バイトが効率的にキャッシュされます。なぜそれが機能するのでしょうか?
コンピューターサイエンスには、 と呼ばれる理論概念があります。これは、かなり大規模なプログラムでは、一度に使用されるのはほんの一部だけであることを意味します。奇妙に思えるかもしれませんが、参照の局所性はほとんどのプログラムで機能します。実行可能ファイルのサイズが 10 メガバイトであっても、そのプログラムから一度に使用されるのはほんの数バイトだけであり、その繰り返し率は非常に高いです。次のページでは、参照の場所について詳しく説明します。
参照の場所
参照の局所性が機能する理由を確認するために、次の疑似コードを見てみましょう (実際に理解するには、 「C プログラミングのしくみ」を参照してください)。
画面に出力 《1~100の数字を入力》
ユーザーからの入力を読み取る
ユーザーからの値を変数 X に入れます
変数Yに値100を入れます
変数 Z に値 1 を入れます
ループY回数
ZをXで割る
割り算の余り = 0 の場合
次に、« Z は X の倍数です » を出力します。
Zに1を加える
ループに戻る
終わり
この小さなプログラムは、ユーザーに 1 から 100 までの数値を入力するように求めます。ユーザーが入力した値を読み取ります。次に、プログラムは 1 から 100 までのすべての数値を、ユーザーが入力した数値で除算します。剰余が 0 (モジュロ除算) かどうかをチェックします。そうである場合、プログラムは 1 から 100 までのすべての数値に対して「Z は X の倍数」(たとえば、12 は 6 の倍数) を出力します。その後、プログラムは終了します。
コンピュータプログラミングにあまり詳しくなくても、このプログラムの11行のうち、ループ部分(7~9行目)が100回実行されることは容易に理解できます。他の行はすべて 1 回だけ実行されます。 7 行目から 9 行目は、キャッシュにより大幅に高速に実行されます。
このプログラムは非常に小さいので、最小の L1 キャッシュに簡単に完全に収まりますが、このプログラムが巨大だとしましょう。結果は同じままです。プログラムを作成するとき、ループ内で多くのアクションが発生します。ワード プロセッサは、時間の 95% を入力の待機と画面への表示に費やします。ワードプロセッサ プログラムのこの部分はキャッシュ内にあります。
この 95% 対 5% の比率 (およそ) は参照の局所性と呼ばれるもので、これがキャッシュが非常に効率的に機能する理由です。これが、このような小さなキャッシュでこのような大規模なメモリ システムを効率的にキャッシュできる理由でもあります。どこでも最速のメモリを搭載したコンピューターを構築することがなぜ価値がないのかがわかります。当社は、わずかなコストでこの効果の 95% を実現できます。