Cache ([], auch []Cache auf duden.de) bezeichnet in der Informationstechnik einen schnellen Pufferspeicher, der (wiederholte) Zugriffe auf vergleichsweise langsame Datenspeicher oder aufwendige Neuberechnungen zu vermeiden hilft. Daten, die bereits einmal geladen oder generiert wurden, verbleiben im Cache, so dass sie bei späterem Bedarf schneller aus diesem abgerufen werden können. Auch können Daten, die vermutlich bald benötigt werden, vorab vom Hintergrundmedium abgerufen und vorerst im Cache bereitgestellt werden ().

Caches können als Hardwarestruktur (beispielsweise als Hauptspeicherchips) oder Softwarestruktur (beispielsweise als temporäre Dateien oder reservierter Speicherplatz) ausgebildet sein.

Geschichte Das Konzept eines schnellen Zwischenspeichers, wie es hier beschrieben ist, wurde erstmals im April 1965 von M. V. Wilkes vorgestellt.

Cache ist ein Lehnwort, das in diesem Zusammenhang vermutlich erstmals bei IBM in Amerika aus dem Französischen entnommen wurde. Zumindest wird es bereits 1973 in einem Aufsatz von K. R. Kaplan, einem Mitarbeiter des Department of Computer Science am Livingston College der Rutgers University in New Jersey, verwendet. Seinen Ursprung hat es im französischen cache, das eigentlich die Bedeutung Versteck hat. Der Name verdeutlicht den Umstand, dass dem Verwender in der Regel der Cache und seine Ersatzfunktion für das angesprochene Hintergrundmedium verborgen bleibt. Wer das Hintergrundmedium verwendet, muss Größe oder Funktionsweise des Caches prinzipiell nicht kennen, denn der Cache wird nicht direkt angesprochen. Der Verwender „spricht das Hintergrundmedium an“, stattdessen „antwortet“ jedoch der Cache – genau auf die Art und Weise, wie auch das Hintergrundmedium geantwortet, also Daten geliefert hätte. Wegen der Unsichtbarkeit dieser zwischengeschalteten Einheit spricht man auch von Transparenz. Praktisch ist er eine gespiegelte Ressource, die stellvertretend für das Original sehr schnell reagiert.

Neuere Geschichte Neben dem Zwischenspeichern von schon benutzten Daten haben moderne Caches die Aufgabe, zukünftig möglicherweise benötigte Daten schon in den Cache vorzuladen. Dies kann softwareunterstützt (PREFETCHT0, PREFETCHT1, PREFETCHT2, PREFETCHNTA) erfolgen (ab 1999/Pentium III) wie auch hardwareunterstützt durch Erkennen typischer Zugriffsmuster (ab 2000/Pentium 4).

Randbedingungen Greifen außer dem den Cache verwendenden Gerät noch weitere auf das Hintergrundmedium zu, so kann es zu Inkonsistenzen kommen. Um auf ein identisches Datenabbild zugreifen zu können, ist es notwendig, vor dem Zugriff die Änderungen des Caches in das Hintergrundmedium zu übernehmen. Cachestrategien wie Write-Through oder Write-Back sind hier praktikabel. Im Extremfall muss ein kompletter „Cache Flush“ erfolgen.

Außerdem muss ggf. der Cache informiert werden, dass sich Daten auf dem Hintergrundmedium geändert haben und sein Inhalt nicht mehr gültig ist (Cache-Kohärenz). Stellt die Cachelogik das nicht sicher, so ergibt sich als Nachteil, dass inzwischen im Hintergrundmedium oder im Rechenprogramm erfolgte Änderungen nicht erkannt werden. Bei Verdacht auf Änderungen, oder um sicherzugehen, dass der aktuelle Stand berücksichtigt wird, muss der Benutzer explizit eine Cache-Aktualisierung veranlassen.

Nutzen Die Ziele beim Einsatz eines Caches sind eine Verringerung der Zugriffszeit und/oder eine Verringerung der Anzahl der Zugriffe auf ein langsames Hintergrundmedium. Das bedeutet insbesondere, dass sich der Einsatz von Caches nur dort lohnt, wo die Zugriffszeit auch signifikanten Einfluss auf die Gesamtleistung hat. Während das z. B. beim Prozessorcache der meisten (skalaren) Mikroprozessoren der Fall ist, trifft es nicht auf Vektorrechner zu, wo die Zugriffszeit eine untergeordnete Rolle spielt. Deswegen wird dort üblicherweise auf Caches verzichtet, weil diese keinen oder nur wenig Nutzen bringen.

Ein weiterer wichtiger Effekt beim Einsatz von Caches ist die Verringerung der notwendigen Datenübertragungsrate an die Anbindung des Hintergrundmediums (siehe z. B. Speicherhierarchie); das Hintergrundmedium kann also „langsamer angebunden“ werden, was z. B. geringere Kosten ergeben kann. Weil oft der Großteil der Anfragen vom Cache beantwortet werden kann („Cache Hit“, s. u.), sinkt die Anzahl der Zugriffe und damit die notwendige Datenübertragungsrate. Zum Beispiel würde ein moderner Mikroprozessor ohne Cache selbst mit sehr kleiner Zugriffszeit des Hauptspeichers dadurch ausgebremst, dass nicht genügend Speicherbandbreite zur Verfügung steht, weil durch den Wegfall des Caches die Anzahl der Zugriffe auf den Hauptspeicher und damit die Anforderung an die Speicherbandbreite stark zunehmen würde.

Bei CPUs kann der Einsatz von Caches somit zum Verringern des Von-Neumann-Flaschenhalses der Von-Neumann-Architektur beitragen. Die Ausführungsgeschwindigkeit von Programmen kann dadurch im Mittel enorm gesteigert werden.

Ein Nachteil von Caches ist das schlecht vorhersagbare Zeitverhalten, da die Ausführungszeit eines Zugriffs aufgrund von Cache-Misses nicht immer konstant ist. Sind die Daten nicht im Cache, muss der Zugreifende warten, bis sie von dem langsamen Hintergrundmedium geladen wurden. Bei Prozessoren geschieht das oft bei Zugriffen auf bisher noch nicht verwendete Daten oder beim Laden des nächsten Programmbefehls bei (weiten) Sprüngen.

Cachehierarchie Da es technisch aufwändig und damit meist wirtschaftlich nicht sinnvoll ist, einen Cache zu bauen, der sowohl groß als auch schnell ist, kann man mehrere Caches verwenden – z. B. einen kleinen schnellen und einen deutlich größeren, jedoch etwas langsameren Cache (der aber immer noch viel schneller ist als der zu cachende Hintergrundspeicher). Damit kann man die konkurrierenden Ziele von geringer Zugriffszeit und großem Cacheumfang gemeinsam realisieren. Das ist wichtig für die Hit Rate.

Existieren mehrere Caches, so bilden diese eine Cachehierarchie, die Teil der Speicherhierarchie ist. Die einzelnen Caches werden nach ihrer Hierarchieebene (engl. ) durchnummeriert, also Level‑1 bis Level‑n oder kurz L1, L2 usw. Je niedriger die Nummer, desto näher liegt der Cache am schnellen „Benutzer“; die niedrigste Nummer bezeichnet daher den Cache mit der schnellsten Zugriffszeit, dieser wird als erstes durchsucht. Enthält der L1-Cache die benötigten Daten nicht, wird der (meist etwas langsamere, aber größere) L2-Cache durchsucht usw. Das geschieht solange, bis die Daten entweder in einer Cacheebene gefunden (ein „Cache Hit“, s. u.) oder alle Caches ohne Erfolg durchsucht wurden (ein „Cache Miss“, s. u.). In letzterem Fall muss auf den langsamen Hintergrundspeicher zugegriffen werden.

Tritt ein Cache Hit z. B. im L3-Cache auf, so werden die angeforderten Daten dem Zugreifer geliefert und zugleich in den L1-Cache übernommen; dafür muss dort eine Cache-Line weichen, die in den L2-Cache „absinkt“.

Bei einem inklusiven Cache ist jeder Cache-Level für sich transparent, d. h. eine Cache-Line, die im L1-Cache ist, ist auch im L2- und L3-Cache vorhanden. Wird die Cache-Line aus dem L1-Cache „verdrängt“ (überschrieben mit Daten einer anderen Adresse), so muss sonst nichts unternommen werden – sie ist im L2-Cache ja immer noch vorhanden (sofern kein Write-Back o. Ä. notwendig ist). Bei einem exklusiven Cache ist eine Cache-Line einer Adresse nur einmal in allen Cache-Levels vorhanden. Eine Cache-Line zu Adresse A im L1-Cache ist nicht zusätzlich im L2- oder L3-Cache vorhanden. Wird sie aus dem L1-Cache verdrängt, so kann sie entweder gänzlich verworfen werden, oder muss explizit in den L2-Cache kopiert werden. Dort wird somit ebenfalls eine (andere) Cache-Line verdrängt, um Platz zu machen für die absinkende. Diese andere sinkt nun ihrerseits in den L3-Cache, wo somit eine dritte Cache-Line weichen muss. Exklusive Cache-Hierarchien erzeugen deutlich mehr Datenverkehr zwischen den Caches. Dafür können so viele Cache-Lines bereitgehalten werden wie die Summe von L1-, L2- und L3-Cache-Größe, während beim inklusiven Cache nur die L3-Cache-Größe maßgebend ist.

Im Hardwarebereich weisen vor allem moderne CPUs zwei oder drei Cacheebenen auf; sonstige Geräte besitzen meist nur eine Cacheebene. Im Softwarebereich wird meist nur eine Cacheebene benutzt, eine prominente Ausnahme bilden Webbrowser, die zwei Ebenen nutzen (Arbeitsspeicher und Festplattenlaufwerk).

Strategien Cachegröße Um den Nutzen des meist um mehrere Zehnerpotenzen kleineren Caches im Vergleich zum Hintergrundspeicher zu maximieren, werden bei der Funktionsweise und Organisation eines Caches die Lokalitätseigenschaften der Zugriffsmuster ausgenutzt. Beobachtet man beispielsweise die Aktivität eines laufenden Programms auf einem Prozessor über ein kurzes Zeitintervall, so stellt man fest, dass wiederholt auf wenige und „immer dieselben“ kleinen Speicherbereiche (z. B. Code innerhalb von Schleifen, Steuervariablen, lokale Variablen und Prozedurparameter) zugegriffen wird. Deshalb können bereits kleine Caches mit einigen Kibibytes sehr wirksam sein.

Verarbeitet ein Algorithmus jedoch ständig neue Daten (z. B. Streaming-Daten), kann ein Cache keine Beschleunigung durch Mehrfach-Zugriffe bewirken, allenfalls geringfügig durch .

Lokalitätsausnutzung Da Caches schnell sein sollen, verwendet man für sie meist eine andere (schnellere) Speichertechnologie als für den zu cachenden Speicher (zum Beispiel SRAM gegenüber DRAM, DRAM gegenüber Magnetscheibe usw.). Daher sind Caches meist wesentlich teurer in Bezug auf das Preis-Bit-Verhältnis, weshalb sie deutlich kleiner ausgelegt werden. Das führt dazu, dass ein Cache nicht alle Daten gleichzeitig vorrätig haben kann. Um das Problem zu lösen, welche Daten im Cache gehalten werden sollen, werden die Lokalitätseigenschaften der Zugriffe ausgenutzt:

Zeitliche (temporale) Lokalität Da sich Zugriffe auf Daten wiederholen (z. B. beim Abarbeiten einer Programmschleife), ist es eher wahrscheinlich, dass auf Daten, auf die schon einmal zugegriffen wurde, auch noch ein weiteres Mal zugegriffen wird. Diese Daten sollten also bevorzugt im Cache gehalten werden. Dadurch ergibt sich auch die Notwendigkeit, alte Daten, die lange nicht benutzt wurden, aus dem Cache zu entfernen, um Platz für neuere zu machen. Diesen Vorgang nennt man „Verdrängung“. Räumliche (spatiale) Lokalität Da Programmcode und -daten nicht zufällig verstreut im Adressraum herumliegen, sondern „hintereinander“ und teilweise auch nur in bestimmten Adressbereichen angeordnet sind (Code-, Daten-, Stack-Segment, Heap usw.), ist es nach einem Zugriff auf eine bestimmte Adresse wahrscheinlich, dass auch auf eine „nahegelegene“ Adresse (sprich: Betrag der Differenz der beiden Adressen sehr klein) zugegriffen wird. Bei der Abarbeitung eines Programms wird z. B. ein Befehl nach dem anderen abgearbeitet, wobei diese „nacheinander“ im Speicher liegen (wenn kein Sprungbefehl dabei ist). Viele Datenstrukturen wie Arrays liegen ebenfalls „hintereinander“ im Speicher.

Cache-Nutzdaten werden in sogenannten Cache-Lines gespeichert, die in den 1990er Jahren 16 oder 32 Byte groß waren und heutzutage 64 oder 128 Bytes groß sind. Dies erfolgt aus folgenden Gründen Pro Cache-Lines werden 5 bis 7 Byte Metadaten benötigt. Daher ist es nicht sinnvoll, für jedes Nutzdaten-Byte jeweils 5 bis 7 Byte für die Metadaten vorzuhalten. Für die Implementierung von ECC-RAM sind immer nur Blocks von 8 Byte bis 64 Bytes schreibbar. Das betrifft Server-ECC-RAM wie auch generell Speicher ab DDR5-RAM. Speicher lesen immer Blocks von 64 oder 128 Byte. Einzelne Bytes sind seit DDR1-RAM nicht mehr lesbar. Meist werden ohnehin 8 bis 64 Byte für einzelne Lesezugriffe benötigt. Die Wahrscheinlichkeit ist hoch, dass benachbarte Speicherzellen in zeitlich kurzem Abstand ohnehin gelesen werden.

Organisation Ein Cache besteht aus einer (meist) festen Anzahl Einträgen, jeder Eintrag besteht aus:

Cache-Line