Cache [kæʃ] bezeichnet in der EDV eine Methode, um Inhalte, die bereits einmal vorlagen, beim nächsten Zugriff schneller zur Verfügung zu stellen. Caches sind als Puffer-Speicher realisiert, die Kopien zwischenspeichern. Sie können als Hardware- oder Softwarestruktur ausgebildet sein.
Gründe für den Einsatz eines Caches sind ein (relativ gesehen) langsamer Zugriff auf ein Hintergrundmedium oder ein relativ hoher Aufwand, oft benötigte Daten neu zu generieren.
Wörtlich aus dem Englischen übersetzt bedeutet Cache (gesprochen käsch, entlehnt vom französischen cacher – verbergen) geheimes Lager. Der Name verdeutlicht den Umstand, dass ein Cache seine Arbeit zumeist im Verborgenen verrichtet. Ein Programmierer muss dessen Größe oder Funktionsweise prinzipiell also nicht kennen, denn der Cache ist als solches abstrakt und wird nicht direkt angesprochen. Praktisch ist er eine gespiegelte Ressource, die stellvertretend für das Original bearbeitet werden kann. Damit alle Geräte auf ein identisches Speicherabbild zugreifen können, ist es notwendig, die Änderungen des Caches in den Hauptspeicher zu übernehmen. Cachestrategien wie Write-Through oder Write-Back sind hier praktikabel. Im Extremfall muss ein kompletter „Cache Flush“ erfolgen.
Inhaltsverzeichnis |
Die Ziele beim Einsatz eines Caches sind eine Verringerung der Zugriffszeit bzw. eine Verringerung der Anzahl der Zugriffe auf den zu cachenden Speicher. 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 bei den meisten (skalaren) Mikroprozessoren der Fall ist, trifft das beispielsweise nicht auf Vektorrechner zu, wo die Zugriffszeit keine sehr wichtige Rolle spielt. Deswegen wird dort üblicherweise auch auf Caches verzichtet, weil diese keinen oder nur wenig Nutzen bringen.
Ein weiterer wichtiger Effekt beim Einsatz von Caches ist die verringerte Bandbreitenanforderung an die nächsthöhere Speicherebene der Speicherhierarchie. Weil oftmals der Großteil der Anfragen vom Cache beantwortet werden kann („Cache Hit“, s. u.), sinkt die Anzahl der Zugriffe und damit die Bandbreitenanforderung an den zu cachenden Speicher. Ein moderner Mikroprozessor ohne Cache würde selbst mit unendlich 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. Ein Cache kann daher also auch genutzt werden, um die Bandbreitenanforderungen an den zu cachenden Speicher zu reduzieren, was sich z. B. in geringeren Kosten für diesen niederschlagen kann.
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 Echtzeitverhalten, da die Ausführungszeit eines Befehls aufgrund von Cache Misses nicht immer konstant ist.
Da es technisch nicht oder nur sehr schwer möglich ist, einen Cache zu bauen, der gleichzeitig sowohl groß als auch schnell ist, kann man mehrere Caches verwenden – z. B. einen kleinen schnellen und einen großen langsameren Cache (der aber immer noch Größenordnungen schneller ist als der zu cachende Speicher). Damit kann man die konkurrierenden Ziele von geringer Zugriffszeit und Cachegröße (wichtig für Hit Rate) gemeinsam realisieren.
Existieren mehrere Caches, so bilden diese eine Cachehierarchie, die Teil der Speicherhierarchie ist. Die einzelnen Caches werden nach ihrer Hierarchieebene (engl. level) durchnummeriert, also Level-1 bis Level-n oder kurz L1, L2 usw. Je niedriger die Nummer, desto hardwarenäher ist der Cache; die niedrigste Nummer bezeichnet daher den Cache mit der kleinsten Zugriffszeit, dieser wird also 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 verhältnismäßig langsamen Speicher zugegriffen werden.
Im Hardwarebereich weisen vor allem moderne CPUs zwei oder drei Cacheebenen auf; sonstige Geräte besitzen aber meist nur eine Cacheebene. Im Softwarebereich wird meist nur eine Cacheebene benutzt, eine prominente Ausnahme bilden aber Webbrowser, die zwei Ebenen nutzen (Arbeitsspeicher und Festplatte).
Um den Nutzen des meist mehrere Größenordnungen 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 kleine Speicherbereiche (z. B. Code innerhalb Schleifen, Steuervariablen, lokale Variablen und Prozedurparameter) zugegriffen wird. Darum können bereits kleine Caches mit einigen Kilobytes sehr wirksam sein.
Bei CPUs kann der Cache direkt im Prozessor integriert oder extern auf der Hauptplatine platziert sein. Je nach Ort des Caches arbeitet dieser mit unterschiedlichen Taktfrequenzen: Der L1 ist fast immer direkt im Prozessor integriert und arbeitet daher mit dem vollen Prozessortakt – also u. U. mehrere Gigahertz. Ein externer Cache hingegen wird oftmals nur mit einigen hundert Megahertz getaktet.
Gängige Größen für L1-Caches sind 4 bis 256 KiB und für den L2-Cache 64 KiB bis 12 MiB.
Moderne Prozessoren haben getrennte L1-Caches für Programme und Daten (Lese- und Schreibcache), teilweise ist das auch noch beim L2 der Fall (Montecito). Man spricht hier von einer Harvard-Cachearchitektur. Das hat den Vorteil, dass man für die unterschiedlichen Zugriffsmuster für das Laden von Programmcode und Daten unterschiedliche Cachedesigns verbauen kann. Außerdem kann man bei getrennten Caches diese räumlich besser zu den jeweiligen Einheiten auf dem Prozessor-Die platzieren und damit die kritischen Pfade beim Prozessorlayout verkürzen. Des Weiteren können Instruktionen und Daten gleichzeitig gelesen/geschrieben werden, wodurch der Von-Neumann-Flaschenhals weiter verringert werden kann. Ein Nachteil ist, dass selbstmodifizierender Code nicht sehr gut auf modernen Prozessoren läuft. Allerdings wird diese Technik heute ohnehin nur noch sehr selten verwendet.
Bei Festplatten befindet sich der Cache auf der Steuerplatine (siehe Festplattencache).
Auch die meisten Laufwerke für optische Speicher besitzen Caches, um die oftmals im dreistelligen Millisekundenbereich liegenden Zugriffszeiten aufzufangen.
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 etc.). Daher sind Caches meist wesentlich teurer in Bezug auf das Preis-Bit-Verhältnis, weswegen Caches 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 denn nun im Cache gehalten werden sollen, werden Lokalitätseigenschaften der Zugriffe ausgenutzt:
Die räumliche Lokalität ist der Grund, warum man bei Caches nicht einzelne Bytes, sondern die Daten ganzer Adressbereiche („Cacheblock“ oder manchmal auch „Cache-Line“ genannt) speichert. Zusätzlich erleichtert das die Implementierung und verringert Speicheroverhead, da man nicht für jedes Datenbyte dessen Adresse im Speicher festhalten muss, sondern nur für jeden Cacheblock (der aus vielen Bytes besteht). Die Wahl der Blockgröße ist ein wichtiger Designparameter für einen Cache, der die Leistung stark beeinflussen kann, positiv wie auch negativ.
Die Blöcke eines Caches können in so genannte Sätze aufgeteilt werden. Für eine gegebene Adresse ist immer ein ganzer Satz zuständig, innerhalb eines Satzes bedienen alle Blöcke also gemeinsam dieselben Adressen. Im Folgenden stehe die Variable m für die Gesamtanzahl der Cacheblöcke und n für die Anzahl der Blöcke pro Satz, die so genannte Assoziativität.
| Organisation | Anzahl der Sätze | Assoziativität |
|---|---|---|
| DM | m | 1 |
| FA | 1 | m bzw. n |
| SA | ![]() |
n |
Je nachdem, wie stark man diese Aufteilung vornimmt, spricht man von einer der drei Cacheorganisationsarten:
direkt abgebildete Caches vollassoziativ (also frei) angewählt. Diesen Cache nennt man dann n-fach satzassoziativ oder kurz n-fach assoziativ. Diese Cacheform stellt einen Kompromiss aus Hardwareaufwand und Effizienz des Caches dar: Gegenüber einem DM-Cache gewinnt man Effizienz, gegenüber einem FA-Cache spart man Hardware.Die ersten beiden sind ein Spezialfall des satzassoziativen Caches. Der direkt abgebildete und der vollassoziative Cache lassen sich somit vom satzassoziativen Cache ableiten: n=1 führt zu einem direkt abgebildeten Cache, n=m zu einem vollassoziativen Cache.
Den Vorgang, dass die Daten einer Anfrage an einen Cache in selbigem vorrätig sind, bezeichnet man als „Cache Hit“ (dt. Cachetreffer), den umgekehrten Fall als „Cache Miss“ (dt. „Cache-Verfehlen“).
Um quantitative Maßzahlen für die Bewertung der Effizienz eines Caches zu erhalten, definiert man zwei Größen:
Dabei werden drei Arten von Cache Misses unterschieden:
Diese drei Typen bezeichnet man auch kurz als „Die drei C“. In Multiprozessorsystemen kann beim Einsatz eines Cache-Kohärenz-Protokolls vom Typ Write-Invalidate noch ein viertes „C“ hinzukommen, nämlich ein „Coherency Miss“: Wenn durch das Schreiben eines Prozessors in einen Cacheblock der gleiche Block im Cache eines zweiten Prozessors hinausgeworfen werden muss, so führt der Zugriff des zweiten Prozessors auf eine Adresse, die durch diesen entfernten Cacheblock abgedeckt war, zu einem Coherency Miss.
Bei der Verwaltung des Caches ist es sinnvoll, immer nur die Blöcke im Cache zu halten, auf die auch häufig zugegriffen wird. Zu diesem Zweck gibt es verschiedene Ersetzungsstrategien. Eine häufig verwendete Variante ist dabei die LRU-Strategie (engl. least recently used), welche immer den am längsten nicht mehr zugegriffenen Block im Cache austauscht. Moderne Prozessoren (AMD Athlon u. v. m.) implementieren meist eine Pseudo-LRU-Ersetzungsstrategie, die also fast wie echtes LRU arbeitet, aber leichter in Hardware zu implementieren ist.
Bei einem Schreibzugriff auf einen Block, der im Cache vorhanden ist, gibt es prinzipiell zwei Möglichkeiten:
Analog zu Obigem gibt es bei einem Schreibzugriff auf einen Block, der nicht im Cache vorhanden ist, prinzipiell ebenso zwei Möglichkeiten:
Einige Befehlssätze enthalten Befehle, die es dem Programmierer ermöglichen, explizit anzugeben, ob zu schreibende Daten am Cache vorbeizuschreiben sind.
Normalerweise wird entweder die Kombination write-back mit write-allocate oder write-through mit non-write-allocate verwendet. Die erste Kombination hat den Vorteil, dass aufeinander folgende Schreibzugriffe auf denselben Block (Lokalitätsprinzip) komplett im Cache abgewickelt werden (bis auf den ersten Miss). Dies gibt im zweiten Fall keinen Vorteil, da sowieso jeder Schreibzugriff zum Hauptspeicher muss, weshalb die Kombination write-through mit write-allocate eher unüblich ist.[1]
Ein Cache Flush („Pufferspeicher-Leerung“) bewirkt das komplette Zurückschreiben des Cacheinhaltes in den Hintergrundspeicher. Dabei bleibt der Cacheinhalt meist unangetastet. Ein solches Vorgehen ist nötig, um die Konsistenz zwischen Cache und Hintergrundspeicher wiederzuherstellen. Notwendig ist das zum Beispiel immer dann, wenn Daten aus dem Hauptspeicher von externen Geräten benötigt werden, unter anderem bei Multiprozessor-Kommunikation oder bei der Übergabe eines als Ausgabepuffer benutzten Teils des Hauptspeichers an den DMA-Controller.
Für jeden Cacheblock wird im Cache folgendes gespeichert:
Ein Cache ist „heiß“, wenn er optimal arbeitet, also gefüllt ist und nur wenige Cache Misses hat; ist das nicht der Fall, gilt der Cache als „kalt“. Ein Cache ist nach Inbetriebnahme zunächst kalt, da er noch keine Daten enthält und häufig zeitraubend Daten nachladen muss, und wärmt sich dann zunehmend auf, da die zwischengelagerten Daten immer mehr den angeforderten entsprechen und weniger Nachladen erforderlich ist. Im Idealzustand werden Datenzugriffe fast ausschließlich aus dem Cache bedient und das Nachladen kann vernachlässigt werden.
Caches können auch bei Software genutzt werden, dabei ist dasselbe Prinzip wie bei der Hardwareimplementierung gemeint: Daten werden für einen schnelleren Zugriff auf ein schnelleres Medium zwischengespeichert.
Beispiele:
Software-Caches werden meist im Form von temporären Dateien angelegt.
Man spricht auch von Caching, wenn ein Betriebssystem gewisse Ressourcen – wie z. B. Funktionsbibliotheken oder Schriftarten – vorerst im Arbeitsspeicher belässt, obwohl sie nach Ende ihrer Benutzung nicht mehr gebraucht werden. So lange kein Speichermangel herrscht, können sie im Arbeitsspeicher verbleiben, um dann ohne Nachladen von der Festplatte sofort zur Verfügung zu stehen, wenn sie wieder gebraucht werden. Wenn allerdings die Speicherverwaltung des Betriebssystems einen Speichermangel feststellt, werden diese Ressourcen als erste gelöscht.
Für Lexikon-Artikel gilt die Lizenz „Creative Commons Attribution/Share Alike“.
Die Wikipedia ist eine Enzyklopädie, deren Inhalte frei nutzbar sind und es immer sein werden.