Hva er LRU Cache?
Buffererstatningsalgoritmer er effektivt utformet for å erstatte hurtigbufferen når plassen er full. De Minst nylig brukt (LRU) er en av disse algoritmene. Som navnet antyder når hurtigbufferminnet er fullt, LRU velger dataene som er minst nylig brukt og fjerner dem for å gi plass til de nye dataene. Prioriteten til dataene i hurtigbufferen endres i henhold til behovet for disse dataene, dvs. hvis noen data hentes eller oppdateres nylig, vil prioriteten til disse dataene bli endret og tildelt den høyeste prioritet, og prioriteten til dataene reduseres hvis den forblir ubrukte operasjoner etter operasjoner.
Innholdsfortegnelse
- Hva er LRU Cache?
- Operasjoner på LRU Cache:
- Arbeid med LRU Cache:
- Måter å implementere LRU Cache:
- LRU-bufferimplementering ved bruk av kø og hashing:
- LRU-bufferimplementering ved hjelp av dobbeltlenkede liste og hashing:
- LRU-bufferimplementering ved hjelp av Deque & Hashmap:
- LRU-bufferimplementering ved bruk av Stack & Hashmap:
- LRU-buffer ved bruk av Counter-implementering:
- LRU-bufferimplementering ved hjelp av Lazy Updates:
- Kompleksitetsanalyse av LRU Cache:
- Fordeler med LRU-cache:
- Ulemper med LRU-cache:
- Real-World-applikasjon av LRU Cache:
LRU Algoritme er et standardproblem, og det kan ha variasjoner etter behov, for eksempel i operativsystemer LRU spiller en avgjørende rolle siden den kan brukes som en sideerstatningsalgoritme for å minimere sidefeil.
Operasjoner på LRU Cache:
- LRUCache (Kapasitet c): Initialiser LRU-cache med positiv størrelseskapasitet c.
- få (nøkkel) : Returnerer verdien av Key ' k' hvis den er til stede i cachen ellers returnerer den -1. Oppdaterer også prioriteten til data i LRU-cachen.
- put (nøkkel, verdi): Oppdater verdien til nøkkelen hvis denne nøkkelen eksisterer. Ellers legger du til nøkkelverdi-paret i hurtigbufferen. Hvis antallet nøkler overskred kapasiteten til LRU-hurtigbufferen, avvis den sist brukte nøkkelen.
Arbeid med LRU Cache:
La oss anta at vi har en LRU-cache med kapasitet 3, og vi ønsker å utføre følgende operasjoner:
- Sett (nøkkel=1, verdi=A) inn i hurtigbufferen
- Sett (nøkkel=2, verdi=B) inn i hurtigbufferen
- Sett (nøkkel=3, verdi=C) inn i hurtigbufferen
- Hent (nøkkel=2) fra hurtigbufferen
- Få (tast=4) fra hurtigbufferen
- Sett (nøkkel=4, verdi=D) inn i hurtigbufferen
- Sett (nøkkel=3, verdi=E) inn i hurtigbufferen
- Få (tast=4) fra hurtigbufferen
- Sett (nøkkel=1, verdi=A) inn i hurtigbufferen
Ovennevnte operasjoner utføres etter hverandre som vist på bildet nedenfor:

Detaljert forklaring av hver operasjon:
- Sett (nøkkel 1, verdi A) : Siden LRU-cachen har tom kapasitet=3, er det ikke behov for noen erstatning, og vi setter {1 : A} øverst, dvs. {1 : A} har høyeste prioritet.
- Sett (nøkkel 2, verdi B) : Siden LRU-hurtigbufferen har tom kapasitet=2, er det igjen ikke behov for noen erstatning, men nå har {2 : B} høyest prioritet og prioritet på {1 : A}-reduksjon.
- Sett (nøkkel 3, verdi C) : Fortsatt er det 1 tom plass ledig i hurtigbufferen, legg derfor inn {3 : C} uten noen erstatning, legg merke til at hurtigbufferen er full og gjeldende prioritetsrekkefølge fra høyeste til laveste er {3:C}, {2:B }, {1:A}.
- Hent (nøkkel 2) : Nå, returner verdien av key=2 under denne operasjonen, også siden key=2 brukes, er den nye prioritetsrekkefølgen nå {2:B}, {3:C}, {1:A}
- Hent (nøkkel 4): Legg merke til at nøkkel 4 ikke er til stede i hurtigbufferen, vi returnerer '-1' for denne operasjonen.
- Sett (nøkkel 4, verdi D) : Legg merke til at cachen er FULL, bruk nå LRU-algoritmen for å bestemme hvilken nøkkel som er minst nylig brukt. Siden {1:A} hadde minst prioritet, fjern {1:A} fra bufferen og legg {4:D} inn i bufferen. Legg merke til at den nye prioriterte rekkefølgen er {4:D}, {2:B}, {3:C}
- Sett (nøkkel 3, verdi E) : Siden nøkkel=3 allerede var til stede i hurtigbufferen med verdi=C, vil denne operasjonen ikke resultere i fjerning av noen nøkkel, snarere vil den oppdatere verdien av nøkkel=3 til ' OG' . Nå vil den nye prioritetsrekkefølgen bli {3:E}, {4:D}, {2:B}
- Hent (nøkkel 4) : Returner verdien til nøkkel=4. Nå vil ny prioritet bli {4:D}, {3:E}, {2:B}
- Sett (nøkkel 1, verdi A) : Siden hurtigbufferen vår er FULL, så bruk LRU-algoritmen vår for å finne ut hvilken nøkkel som ble brukt minst nylig, og siden {2:B} hadde minst prioritet, fjern {2:B} fra hurtigbufferen og sett {1:A} inn i cache. Nå er den nye prioriterte rekkefølgen {1:A}, {4:D}, {3:E}
Måter å implementere LRU Cache:
LRU-cache kan implementeres på en rekke måter, og hver programmerer kan velge en annen tilnærming. Nedenfor er imidlertid vanlige tilnærminger:
- LRU bruker Queue og Hashing
- LRU bruker Dobbeltkoblet liste + hashing
- LRU bruker Deque
- LRU bruker Stack
- LRU bruker Motimplementering
- LRU bruker Lazy Updates
LRU-bufferimplementering ved bruk av kø og hashing:
Vi bruker to datastrukturer for å implementere en LRU Cache.
- Kø implementeres ved hjelp av en dobbeltlenket liste. Maksimal størrelse på køen vil være lik det totale antallet tilgjengelige rammer (cache-størrelse). De sist brukte sidene vil være nær frontenden, og de minst nylig brukte sidene vil være nær bakenden.
- En Hash med sidenummeret som nøkkel og adressen til den tilsvarende kønoden som verdi.
Når det refereres til en side, kan den nødvendige siden være i minnet. Hvis det er i minnet, må vi koble fra noden på listen og bringe den foran i køen.
Hvis den nødvendige siden ikke er i minnet, tar vi den med i minnet. Med enkle ord legger vi til en ny node foran i køen og oppdaterer den tilsvarende nodeadressen i hashen. Hvis køen er full, det vil si at alle rammene er fulle, fjerner vi en node fra baksiden av køen, og legger til den nye noden foran i køen.
Illustrasjon:
La oss vurdere operasjonene, Refererer nøkkel x med i LRU-cachen: { 1, 2, 3, 4, 1, 2, 5, 1, 2, 3 }
Merk: Til å begynne med er det ingen side i minnet.Bildene nedenfor viser trinnvis utførelse av operasjonene ovenfor på LRU-cachen.
Algoritme:
- Lag en klasse LRUCache med erklære en liste av typen int, et uordnet kart av typen
, og en variabel for å lagre maksimal størrelse på hurtigbufferen - I referansefunksjonen til LRUCache
- Hvis denne verdien ikke er til stede i køen, skyv denne verdien foran køen og fjern den siste verdien hvis køen er full
- Hvis verdien allerede er til stede, fjern den fra køen og skyv den foran i køen
- I displayfunksjonen skrive ut, LRUCache ved hjelp av køen starter fra forsiden
Nedenfor er implementeringen av tilnærmingen ovenfor:
C++
// We can use stl container list as a double> // ended queue to store the cache keys, with> // the descending time of reference from front> // to back and a set container to check presence> // of a key. But to fetch the address of the key> // in the list using find(), it takes O(N) time.> // This can be optimized by storing a reference> // (iterator) to each key in a hash map.> #include> using> namespace> std;> > class> LRUCache {> >// store keys of cache> >list<>int>>dq;> > >// store references of key in cache> >unordered_map<>int>, list<>int>>::iterator> ma;> >int> csize;>// maximum capacity of cache> > public>:> >LRUCache(>int>);> >void> refer(>int>);> >void> display();> };> > // Declare the size> LRUCache::LRUCache(>int> n) { csize = n; }> > // Refers key x with in the LRU cache> void> LRUCache::refer(>int> x)> {> >// not present in cache> >if> (ma.find(x) == ma.end()) {> >// cache is full> >if> (dq.size() == csize) {> >// delete least recently used element> >int> last = dq.back();> > >// Pops the last element> >dq.pop_back();> > >// Erase the last> >ma.erase(last);> >}> >}> > >// present in cache> >else> >dq.erase(ma[x]);> > >// update reference> >dq.push_front(x);> >ma[x] = dq.begin();> }> > // Function to display contents of cache> void> LRUCache::display()> {> > >// Iterate in the deque and print> >// all the elements in it> >for> (>auto> it = dq.begin(); it != dq.end(); it++)> >cout << (*it) <<>' '>;> > >cout << endl;> }> > // Driver Code> int> main()> {> >LRUCache ca(4);> > >ca.refer(1);> >ca.refer(2);> >ca.refer(3);> >ca.refer(1);> >ca.refer(4);> >ca.refer(5);> >ca.display();> > >return> 0;> }> // This code is contributed by Satish Srinivas> |
>
>
C
android versjonshistorikk
// A C program to show implementation of LRU cache> #include> #include> > // A Queue Node (Queue is implemented using Doubly Linked> // List)> typedef> struct> QNode {> >struct> QNode *prev, *next;> >unsigned> >pageNumber;>// the page number stored in this QNode> } QNode;> > // A Queue (A FIFO collection of Queue Nodes)> typedef> struct> Queue {> >unsigned count;>// Number of filled frames> >unsigned numberOfFrames;>// total number of frames> >QNode *front, *rear;> } Queue;> > // A hash (Collection of pointers to Queue Nodes)> typedef> struct> Hash {> >int> capacity;>// how many pages can be there> >QNode** array;>// an array of queue nodes> } Hash;> > // A utility function to create a new Queue Node. The queue> // Node will store the given 'pageNumber'> QNode* newQNode(unsigned pageNumber)> {> >// Allocate memory and assign 'pageNumber'> >QNode* temp = (QNode*)>malloc>(>sizeof>(QNode));> >temp->pageNumber = pageNumber;> > >// Initialize prev and next as NULL> >temp->prev = temp->neste = NULL;> > >return> temp;> }> > // A utility function to create an empty Queue.> // The queue can have at most 'numberOfFrames' nodes> Queue* createQueue(>int> numberOfFrames)> {> >Queue* queue = (Queue*)>malloc>(>sizeof>(Queue));> > >// The queue is empty> >queue->telle = 0;> >queue->front = kø->bak = NULL;> > >// Number of frames that can be stored in memory> >queue->numberOfFrames = numberOfFrames;> > >return> queue;> }> > // A utility function to create an empty Hash of given> // capacity> Hash* createHash(>int> capacity)> {> >// Allocate memory for hash> >Hash* hash = (Hash*)>malloc>(>sizeof>(Hash));> >hash->kapasitet = kapasitet;> > >// Create an array of pointers for referring queue nodes> >hash->array> >= (QNode**)>malloc>(hash->kapasitet *>sizeof>(QNode*));> > >// Initialize all hash entries as empty> >int> i;> >for> (i = 0; i capacity; ++i)> >hash->array[i] = NULL;> > >return> hash;> }> > // A function to check if there is slot available in memory> int> AreAllFramesFull(Queue* queue)> {> >return> queue->telle == kø->antall rammer;> }> > // A utility function to check if queue is empty> int> isQueueEmpty(Queue* queue)> {> >return> queue->bak == NULL;> }> > // A utility function to delete a frame from queue> void> deQueue(Queue* queue)> {> >if> (isQueueEmpty(queue))> >return>;> > >// If this is the only node in list, then change front> >if> (queue->foran == kø->bak)> >queue->foran = NULL;> > >// Change rear and remove the previous rear> >QNode* temp = queue->bak;> >queue->bak = kø->bak->prev;> > >if> (queue->bak)> >queue->bak->neste = NULL;> > >free>(temp);> > >// decrement the number of full frames by 1> >queue->telle--;> }> > // A function to add a page with given 'pageNumber' to both> // queue and hash> void> Enqueue(Queue* queue, Hash* hash, unsigned pageNumber)> {> >// If all frames are full, remove the page at the rear> >if> (AreAllFramesFull(queue)) {> >// remove page from hash> >hash->array[queue->rear->pageNumber] = NULL;> >deQueue(queue);> >}> > >// Create a new node with given page number,> >// And add the new node to the front of queue> >QNode* temp = newQNode(pageNumber);> >temp->neste = kø->front;> > >// If queue is empty, change both front and rear> >// pointers> >if> (isQueueEmpty(queue))> >queue->bak = kø->front = temp;> >else> // Else change the front> >{> >queue->front->prev = temp;> >queue->foran = temp;> >}> > >// Add page entry to hash also> >hash->array[sidenummer] = temp;> > >// increment number of full frames> >queue->telle++;> }> > // This function is called when a page with given> // 'pageNumber' is referenced from cache (or memory). There> // are two cases:> // 1. Frame is not there in memory, we bring it in memory> // and add to the front of queue> // 2. Frame is there in memory, we move the frame to front> // of queue> void> ReferencePage(Queue* queue, Hash* hash,> >unsigned pageNumber)> {> >QNode* reqPage = hash->array[sidenummer];> > >// the page is not in cache, bring it> >if> (reqPage == NULL)> >Enqueue(queue, hash, pageNumber);> > >// page is there and not at front, change pointer> >else> if> (reqPage != queue->foran) {> >// Unlink rquested page from its current location> >// in queue.> >reqPage->prev->neste = reqPage->neste;> >if> (reqPage->neste)> >reqPage->next->prev = reqPage->prev;> > >// If the requested page is rear, then change rear> >// as this node will be moved to front> >if> (reqPage == queue->bak) {> >queue->bak = reqPage->prev;> >queue->bak->neste = NULL;> >}> > >// Put the requested page before current front> >reqPage->neste = kø->front;> >reqPage->forrige = NULL;> > >// Change prev of current front> >reqPage->neste->prev = reqPage;> > >// Change front to the requested page> >queue->front = reqPage;> >}> }> > // Driver code> int> main()> {> >// Let cache can hold 4 pages> >Queue* q = createQueue(4);> > >// Let 10 different pages can be requested (pages to be> >// referenced are numbered from 0 to 9> >Hash* hash = createHash(10);> > >// Let us refer pages 1, 2, 3, 1, 4, 5> >ReferencePage(q, hash, 1);> >ReferencePage(q, hash, 2);> >ReferencePage(q, hash, 3);> >ReferencePage(q, hash, 1);> >ReferencePage(q, hash, 4);> >ReferencePage(q, hash, 5);> > >// Let us print cache frames after the above referenced> >// pages> >printf>(>'%d '>, q->forside->sidenummer);> >printf>(>'%d '>, q->forside->neste->sidenummer);> >printf>(>'%d '>, q->front->neste->neste->sidenummer);> >printf>(>'%d '>, q->front->neste->neste->neste->sidenummer);> > >return> 0;> }> |
>
>
Java
/* We can use Java inbuilt Deque as a double> >ended queue to store the cache keys, with> >the descending time of reference from front> >to back and a set container to check presence> >of a key. But remove a key from the Deque using> >remove(), it takes O(N) time. This can be> >optimized by storing a reference (iterator) to> >each key in a hash map. */> import> java.util.Deque;> import> java.util.HashSet;> import> java.util.Iterator;> import> java.util.LinkedList;> > public> class> LRUCache {> > >// store keys of cache> >private> Deque doublyQueue;> > >// store references of key in cache> >private> HashSet hashSet;> > >// maximum capacity of cache> >private> final> int> CACHE_SIZE;> > >LRUCache(>int> capacity)> >{> >doublyQueue =>new> LinkedList();> >hashSet =>new> HashSet();> >CACHE_SIZE = capacity;> >}> > >/* Refer the page within the LRU cache */> >public> void> refer(>int> page)> >{> >if> (!hashSet.contains(page)) {> >if> (doublyQueue.size() == CACHE_SIZE) {> >int> last = doublyQueue.removeLast();> >hashSet.remove(last);> >}> >}> >else> {>/* The found page may not be always the last> >element, even if it's an intermediate> >element that needs to be removed and added> >to the start of the Queue */> >doublyQueue.remove(page);> >}> >doublyQueue.push(page);> >hashSet.add(page);> >}> > >// display contents of cache> >public> void> display()> >{> >Iterator itr = doublyQueue.iterator();> >while> (itr.hasNext()) {> >System.out.print(itr.next() +>' '>);> >}> >}> > >// Driver code> >public> static> void> main(String[] args)> >{> >LRUCache cache =>new> LRUCache(>4>);> >cache.refer(>1>);> >cache.refer(>2>);> >cache.refer(>3>);> >cache.refer(>1>);> >cache.refer(>4>);> >cache.refer(>5>);> >cache.display();> >}> }> // This code is contributed by Niraj Kumar> |
>
>
Python3
# We can use stl container list as a double> # ended queue to store the cache keys, with> # the descending time of reference from front> # to back and a set container to check presence> # of a key. But to fetch the address of the key> # in the list using find(), it takes O(N) time.> # This can be optimized by storing a reference> # (iterator) to each key in a hash map.> class> LRUCache:> ># store keys of cache> >def> __init__(>self>, n):> >self>.csize>=> n> >self>.dq>=> []> >self>.ma>=> {}> > > ># Refers key x with in the LRU cache> >def> refer(>self>, x):> > ># not present in cache> >if> x>not> in> self>.ma.keys():> ># cache is full> >if> len>(>self>.dq)>=>=> self>.csize:> ># delete least recently used element> >last>=> self>.dq[>->1>]> > ># Pops the last element> >ele>=> self>.dq.pop();> > ># Erase the last> >del> self>.ma[last]> > ># present in cache> >else>:> >del> self>.dq[>self>.ma[x]]> > ># update reference> >self>.dq.insert(>0>, x)> >self>.ma[x]>=> 0>;> > ># Function to display contents of cache> >def> display(>self>):> > ># Iterate in the deque and print> ># all the elements in it> >print>(>self>.dq)> > # Driver Code> ca>=> LRUCache(>4>)> > ca.refer(>1>)> ca.refer(>2>)> ca.refer(>3>)> ca.refer(>1>)> ca.refer(>4>)> ca.refer(>5>)> ca.display()> # This code is contributed by Satish Srinivas> |
>
>
C#
// C# program to implement the approach> > using> System;> using> System.Collections.Generic;> > class> LRUCache {> >// store keys of cache> >private> List<>int>>doubleQueue;> > >// store references of key in cache> >private> HashSet<>int>>hashSet;> > >// maximum capacity of cache> >private> int> CACHE_SIZE;> > >public> LRUCache(>int> capacity)> >{> >doublyQueue =>new> List<>int>>();> >hashSet =>new> HashSet<>int>>();> >CACHE_SIZE = capacity;> >}> > >/* Refer the page within the LRU cache */> >public> void> Refer(>int> page)> >{> >if> (!hashSet.Contains(page)) {> >if> (doublyQueue.Count == CACHE_SIZE) {> >int> last> >= doublyQueue[doublyQueue.Count - 1];> >doublyQueue.RemoveAt(doublyQueue.Count - 1);> >hashSet.Remove(last);> >}> >}> >else> {> >/* The found page may not be always the last> >element, even if it's an intermediate> >element that needs to be removed and added> >to the start of the Queue */> >doublyQueue.Remove(page);> >}> >doublyQueue.Insert(0, page);> >hashSet.Add(page);> >}> > >// display contents of cache> >public> void> Display()> >{> >foreach>(>int> page>in> doublyQueue)> >{> >Console.Write(page +>' '>);> >}> >}> > >// Driver code> >static> void> Main(>string>[] args)> >{> >LRUCache cache =>new> LRUCache(4);> >cache.Refer(1);> >cache.Refer(2);> >cache.Refer(3);> >cache.Refer(1);> >cache.Refer(4);> >cache.Refer(5);> >cache.Display();> >}> }> > // This code is contributed by phasing17> |
>
>
Javascript
// JS code to implement the approach> class LRUCache {> >constructor(n) {> >this>.csize = n;> >this>.dq = [];> >this>.ma =>new> Map();> >}> > >refer(x) {> >if> (!>this>.ma.has(x)) {> >if> (>this>.dq.length ===>this>.csize) {> >const last =>this>.dq[>this>.dq.length - 1];> >this>.dq.pop();> >this>.ma.>delete>(last);> >}> >}>else> {> >this>.dq.splice(>this>.dq.indexOf(x), 1);> >}> > >this>.dq.unshift(x);> >this>.ma.set(x, 0);> >}> > >display() {> >console.log(>this>.dq);> >}> }> > const cache =>new> LRUCache(4);> > cache.refer(1);> cache.refer(2);> cache.refer(3);> cache.refer(1);> cache.refer(4);> cache.refer(5);> cache.display();> > // This code is contributed by phasing17> |
>
>
LRU-cache-implementering ved hjelp av Doubly Linked List og Hashing :
Ideen er veldig grunnleggende, dvs. fortsett å sette inn elementene på hodet.
- hvis elementet ikke er til stede i listen, legg det til øverst på listen
- hvis elementet er til stede i listen, flytt elementet til hodet og flytt det gjenværende elementet i listen
Merk at nodens prioritet vil avhenge av avstanden til noden fra hodet, jo nærmest noden er hodet, jo høyere prioritet har den. Så når Cache-størrelsen er full og vi trenger å fjerne et element, fjerner vi elementet ved siden av halen på den dobbeltkoblede listen.
LRU cache-implementering ved hjelp av Deque & Hashmap:
Deque-datastrukturen tillater innsetting og sletting fra fronten så vel som slutten, denne egenskapen tillater implementering av LRU mulig da Front-elementet kan representere høyprioritetselement mens sluttelementet kan være lavprioritetselementet, dvs. Minst nylig brukt.
Arbeider:
- Få operasjon : Sjekker om nøkkelen finnes i hurtigbufferens hash-kart og følg tilfellene nedenfor på deque:
- Hvis nøkkelen blir funnet:
- Varen anses som nylig brukt, så den flyttes til forsiden av dekket.
- Verdien knyttet til nøkkelen returneres som et resultat av
get>operasjon.- Hvis nøkkelen ikke blir funnet:
- returner -1 for å indikere at ingen slik nøkkel er til stede.
- Sett operasjon: Sjekk først om nøkkelen allerede eksisterer i cachens hash-kart og følg sakene nedenfor på dequen
- Hvis nøkkelen finnes:
- Verdien knyttet til nøkkelen oppdateres.
- Gjenstanden flyttes til forsiden av dekket siden den nå er den sist brukte.
- Hvis nøkkelen ikke finnes:
- Hvis hurtigbufferen er full, betyr det at et nytt element må settes inn, og det minst nylig brukte elementet må kastes ut. Dette gjøres ved å fjerne elementet fra slutten av dequen og den tilsvarende oppføringen fra hash-kartet.
- Det nye nøkkelverdi-paret settes deretter inn i både hash-kartet og forsiden av dequen for å indikere at det er det sist brukte elementet
LRU-bufferimplementering ved bruk av Stack & Hashmap:
Implementering av en LRU (Least Recently Used) cache ved å bruke en stabeldatastruktur og hashing kan være litt vanskelig fordi en enkel stabel ikke gir effektiv tilgang til det minst nylig brukte elementet. Du kan imidlertid kombinere en stabel med et hash-kart for å oppnå dette effektivt. Her er en tilnærming på høyt nivå for å implementere den:
- Bruk et Hash-kart : Hash-kartet vil lagre nøkkelverdi-parene til hurtigbufferen. Nøklene vil kartlegges til de tilsvarende nodene i stabelen.
- Bruk en stabel : Stabelen vil opprettholde rekkefølgen på nøkler basert på bruken. Det minst nylig brukte elementet vil være nederst i stabelen, og det sist brukte elementet vil være øverst
Denne tilnærmingen er ikke så effektiv og brukes derfor ikke ofte.
LRU-buffer ved bruk av Counter-implementering:
Hver blokk i cachen vil ha sin egen LRU-teller hvor verdien til telleren hører til {0 til n-1} , her ' n ' representerer størrelsen på cachen. Blokken som endres under utskifting av blokk blir MRU-blokken, og som et resultat endres dens tellerverdi til n – 1. Tellerverdiene som er større enn den åpnede blokkens tellerverdi, reduseres med én. De resterende blokkene er uendret.
| Verdien av Conter | Prioritet | Brukt status |
|---|---|---|
| 0 | Lav | Minst nylig brukt |
| n-1 | Høy | Sist brukt |
LRU-bufferimplementering ved hjelp av Lazy Updates:
Implementering av en LRU (Least Recently Used) cache ved hjelp av late oppdateringer er en vanlig teknikk for å forbedre effektiviteten til cachens operasjoner. Late oppdateringer innebærer å spore rekkefølgen som elementer er tilgjengelig uten umiddelbart å oppdatere hele datastrukturen. Når en cache-miss oppstår, kan du bestemme om du vil utføre en full oppdatering basert på noen kriterier.
Kompleksitetsanalyse av LRU Cache:
- Tidskompleksitet:
- Put()-operasjon: O(1) dvs. tiden som kreves for å sette inn eller oppdatere nytt nøkkelverdi-par er konstant
- Get() operasjon: O(1) dvs. tiden som kreves for å få verdien til en nøkkel er konstant
- Hjelpeplass: O(N) hvor N er kapasiteten til hurtigbufferen.
Fordeler med LRU-cache:
- Rask tilgang : Det tar O(1) tid å få tilgang til dataene fra LRU-cachen.
- Rask oppdatering : Det tar O(1) tid å oppdatere et nøkkelverdi-par i LRU-cachen.
- Rask fjerning av minst nylig brukte data : Det tar O(1) å slette det som ikke har vært nylig brukt.
- Ingen tøffing: LRU er mindre utsatt for thrashing sammenlignet med FIFO fordi den tar hensyn til brukshistorikken til sider. Den kan oppdage hvilke sider som brukes ofte og prioritere dem for minneallokering, noe som reduserer antall sidefeil og disk I/O-operasjoner.
Ulemper med LRU-cache:
- Det krever stor hurtigbufferstørrelse for å øke effektiviteten.
- Det krever ytterligere datastruktur for å bli implementert.
- Maskinvarehjelpen er høy.
- I LRU er feildeteksjon vanskelig sammenlignet med andre algoritmer.
- Det har begrenset aksept.
Real-World-applikasjon av LRU Cache:
- I databasesystemer for raske søkeresultater.
- I operativsystemer for å minimere sidefeil.
- Tekstredigerere og IDE-er for å lagre ofte brukte filer eller kodebiter
- Nettverksrutere og -svitsjer bruker LRU for å øke effektiviteten til datanettverk
- I kompilatoroptimaliseringer
- Verktøy for tekstprediksjon og autofullføring