この問題を避けるには、リタグ(ReTag)という方法が用いられる。図5.11では、OSがキャッシュの青の領域のラインに書き込みを行い、アプリケーションが緑の領域のキャッシュラインをアクセスすると、そこには目的のデータは無いのでタグは一致せず、キャッシュミスになる。そして2次キャッシュにアクセスが行われることになる。

1次キャッシュのアクセスと並行してTLBをアクセスすれば、2次キャッシュのアクセスまでに物理アドレスが得られるので、2次キャッシュはアクセス時間のオーバヘッド無しに物理アドレスをインデックスとするPhysically Indexedのキャッシュとすることができる。したがって、2次キャッシュはVirtual Synonymの問題はなく、ピンクで示された物理ページの中の要求したキャッシュラインが2次キャッシュに存在するかどうかを判定できる。

そして、ここがミソであるが、その物理アドレスのキャッシュラインが1次キャッシュの青の領域にある場合は、そのキャッシュラインを緑の領域に移動する。具体的には、1次キャッシュのそのラインの内容が書き換えられていない場合や、1次キャッシュがWrite Through方式の場合はそのままで良いが、1次キャッシュがWrite Back方式でラインの内容が書き換えられている場合は、そのキャッシュラインを2次キャッシュに書き戻してから、1次キャッシュの対応するキャッシュラインをインバリデートし、キャッシュミスを起こしたキャッシュラインのデータを1次キャッシュに送り、1次キャッシュは、これを緑の部分のキャッシュラインに格納する。

結果として1次キャッシュとしては同じデータが(ページサイズ分だけアドレスが異なる)別のキャッシュラインに格納されるのであるが、これをリタグと呼んでいる。 同じ物理アドレスのページを仮想アドレスの偶数ページにマップするプロセスと、奇数ページにマップするプロセスのアクセスが頻繁に入れ替わるとキャッシュラインの移動のロスが大きくなってしまうが、前述のOSとアプリケーションプロセスの例のように、切り替わりの頻度が低い場合は、問題にならない。

ここまでの説明ではキャッシュのwayサイズがページサイズの2倍としてきたが、ページサイズの4倍とか8倍でも同様に動作させることが出来る。ただし、Virtual Synonymの数が多くなると、リタグの頻度も増加して性能が低下するので、この倍数をあまり多く取るのは適切でない。

AMDの4コアOpteronプロセサはx86互換の4KBのページサイズをサポートしているが、2wayで64KBというページサイズより大きな1次キャッシュを装備しており、具体的な方式は公表されていないが、このようなリタグを行っていると思われる。

なお、図5.10ではTLBの出力とタグを比較しており、タグは物理アドレスである。ということで、この方式はインデックスがVirtual、タグがPhysicalなので、Virtually Indexed Physically Tagged (VIPT)方式と言われる。図5.8のTLBで変換したアドレスをインデックスに使う方式はPIPT(Physically Indexed Physically Tagged)方式である。

実装例は多くないが、1次キャッシュの前に、非常に小容量で高速の0次キャッシュを設ける例がある。このような実装では、インデックスは当然、仮想アドレスであるが、タグも仮想アドレスとするVirtually Indexed Virtually Tagged (VIVT)方式が使われる。VIVT方式ではTLBはまったく関係ないので、アクセス時間は小容量のキャッシュアレイだけで決まり高速のアクセスが可能である。しかし、Virtually Taggedの場合は、プロセスが切り替わって別の仮想空間になると仮想アドレスのタグは意味が無くなってしまうので、プロセスの切り替えに伴いキャッシュ全体をフラッシュする必要がある。

また、理論的にはPhysically Indexed Virtually Tagged(PIVT)という方式も在り得るが、実装上、まったくメリットが無いので、PIVT方式の実装例は聞いたことが無い。

キャッシュとメモリ管理について長々と解説して来たが、このシリーズは今回で終わりで、次回からは、アウトオブオーダ実行などのコアの高性能化について述べる予定である。