Page Faults in LRU | Implementation

LRU uses the concept of paging for memory management, a page replacement algorithm is needed to decide which page needs to be replaced when the new page comes in. Whenever a new page is referred to and is not present in memory, the page fault occurs and the Operating System replaces one of the existing pages with a newly needed page. LRU is one such page replacement policy in which the least recently used pages are replaced.

For example:
Given a sequence of pages in an array of pages[] of length N and memory capacity C, find the number of page faults using the Least Recently Used (LRU) Algorithm.

Example-1 :

`Input : N = 7, C = 3pages = {1, 2, 1, 4, 2, 3, 5}Output : 5`

Explanation :

`Capacity is 3, thus, we can store maximum 3 pages at a time.Page 1 is required, since it is not present, it is a page fault: page fault = 1Page 2 is required, since it is not present, it is a page fault: page fault = 1 + 1 = 2Page 1 is required, since it is present, it is not a page fault: page fault = 2 + 0 = 2Page 4 is required, since it is not present, it is a page fault: page fault = 2 + 1 = 3Page 2 is required, since it is present, it is not a page fault: page fault = 3 + 0 = 3Page 3 is required, since it is not present, it replaces LRU page 2: page fault = 3 + 1 = 4Page 5 is required, since it is not present, it replaces LRU page 1: page fault = 4 + 1 = 5`

Example-2 :

`Input : N = 9, C = 4Pages = {5, 0, 1, 3, 2, 4, 1, 0, 5}Output : 8`

Explanation :

`Capacity is 4, thus, we can store maximum 4 pages at a time.Page 5 is required, since it is not present, it is a page fault: page fault = 1Page 0 is required, since it is not present, it is a page fault: page fault = 1 + 1 = 2Page 1 is required, since it is not present, it is a page fault: page fault = 2 + 1 = 3Page 3 is required, since it is not present, it is a page fault: page fault = 3 + 1 = 4Page 2 is required, since it is not present, it replaces LRU page 5: page fault = 4 + 1 = 5Page 4 is required, since it is not present, it replaces LRU page 0: page fault = 5 + 1 = 6Page 1 is required, since it is present, it is not a page fault: page fault = 6 + 0 = 6Page 0 is required, since it is not present, it replaces LRU page 3: page fault = 6 + 1 = 7Page 5 is required, since it is not present, it replaces LRU page 2: page fault = 7 + 1 = 8`

Algorithm :

`step-1 : Initialize count as 0.step-2 : Create a vector / array of size equal to memory capacity.step-3 : Traverse elements of pages[]step-4 : In each traversal:        if(element is present in memory):            remove the element and push the element at the end          else:            if(memory is full) remove the first element            Increment count             push the element at the end       `

Implementation of the algorithm :

Following is the implementation of the algorithm in C++ as follows.

C++

 `// C++ program to illustrate``// page faults in LRU` `#include ``using` `namespace` `std;` `/* Counts no. of page faults */``int` `pageFaults(``int` `n, ``int` `c, ``int` `pages[])``{``    ``// Initialise count to 0``    ``int` `count = 0;` `    ``// To store elements in memory of size c``    ``vector<``int``> v;``    ``int` `i;``    ``for` `(i = 0; i <= n - 1; i++) {` `        ``// Find if element is present in memory or not``        ``auto` `it = find(v.begin(), v.end(), pages[i]);` `        ``// If element is not present``        ``if` `(it == v.end()) {` `            ``// If memory is full``            ``if` `(v.size() == c) {``              ` `                ``// Remove the first element``                ``// As it is least recently used``                ``v.erase(v.begin());``            ``}` `            ``// Add the recent element into memory``            ``v.push_back(pages[i]);` `            ``// Increment the count``            ``count++;``        ``}``        ``else` `{` `            ``// If element is present``            ``// Remove the element``            ``// And add it at the end as it is``            ``// the most recent element``            ``v.erase(it);``            ``v.push_back(pages[i]);``        ``}``    ``}` `    ``// Return total page faults``    ``return` `count;``}` `/* Driver program to test pageFaults function*/``int` `main()``{` `    ``int` `pages[] = { 1, 2, 1, 4, 2, 3, 5 };``    ``int` `n = 7, c = 3;` `    ``cout << ``"Page Faults = "` `<< pageFaults(n, c, pages);``    ``return` `0;``}` `// This code is contributed by rajsanghavi9.`

Java

 `// Java program to illustrate``// page faults in LRU``import` `java.util.*;``class` `GFG {``  ``public` `static` `void` `main(String[] args)``  ``{``    ``int` `pages[] = ``new` `int``[] { ``1``, ``2``, ``1``, ``4``, ``2``, ``3``, ``5` `};``    ``int` `n = ``7``, c = ``3``;` `    ``System.out.println(``"Page Faults = "``                       ``+ pageFaults(n, c, pages));``  ``}``  ``static` `int` `pageFaults(``int` `N, ``int` `C, ``int` `pages[])``  ``{``    ``// a queue to maintain page frames``    ``Queue q = ``new` `LinkedList<>();` `    ``// starting with 0 page faults``    ``int` `i = ``0``, c = ``0``;``    ``while` `(i < N) ``    ``{` `      ``// if queue is empty or the current page is``      ``// absent in the page frame then page fault``      ``// occurs``      ``if` `(q.isEmpty() || !q.contains(pages[i]))``      ``{``        ``if` `(q.size()== C) ``// if frame is full we remove the``          ``// least recently used page``          ``q.poll(); ``// removing the front element``        ``// which is not replaced for``        ``// long time` `        ``q.add(pages[i]); ``// now we add the page to``        ``// frame``        ``c++; ``// incrementing page faults``      ``}``      ``else``      ``{``        ``q.remove(pages[i]); ``// if the page already exists``        ``// we'll remove it from``        ``// previous position and add``        ``// it to the end of the queue``        ``q.add(pages[i]);``      ``}` `      ``i++;``    ``}``    ``return` `c;``  ``}``}``// This code is contributed by tharunmadishetti1.`

Python3

 `# Python program to illustrate``# page faults in LRU` `# Counts no. of page faults``def` `pageFaults(n, c, pages):` `    ``# Initialise count to 0``    ``count ``=` `0` `    ``# To store elements in memory of size c``    ``v ``=` `[]` `    ``# Iterate through all elements of pages``    ``for` `i ``in` `range``(n):` `        ``# Find if element is present in memory or not``        ``if` `pages[i] ``not` `in` `v:` `            ``# If memory is full``            ``if` `len``(v) ``=``=` `c:` `                ``# Remove the first element``                ``# As it is least recently used``                ``v.pop(``0``)` `            ``# Add the recent element into memory``            ``v.append(pages[i])` `            ``# Increment the count``            ``count ``+``=` `1``        ``else``:` `            ``# If element is present``            ``# Remove the element``            ``# And add it at the end as it is``            ``# the most recent element``            ``v.remove(pages[i])``            ``v.append(pages[i])` `    ``# Return total page faults``    ``return` `count`  `# Driver program to test pageFaults function``pages ``=` `[``1``, ``2``, ``1``, ``4``, ``2``, ``3``, ``5``]``n ``=` `7``c ``=` `3` `print``(``"Page Faults ="``, pageFaults(n, c, pages))` `# This code is contributed by ishankhandelwals.`

C#

 `using` `System;``using` `System.Collections.Generic;` `namespace` `pageFaults {``  ``class` `Program ``  ``{` `    ``/* Counts no. of page faults */``    ``static` `int` `pageFaults(``int` `n, ``int` `c, ``int``[] pages)``    ``{``      ``// Initialise count to 0``      ``int` `count = 0;` `      ``// To store elements in memory of size c``      ``List<``int``> v = ``new` `List<``int``>();``      ``int` `i;``      ``for` `(i = 0; i <= n - 1; i++) {` `        ``// Find if element is present in memory or not``        ``int` `it = v.IndexOf(pages[i]);` `        ``// If element is not present``        ``if` `(it == -1) {` `          ``// If memory is full``          ``if` `(v.Count == c) {` `            ``// Remove the first element``            ``// As it is least recently used``            ``v.RemoveAt(0);``          ``}` `          ``// Add the recent element into memory``          ``v.Add(pages[i]);` `          ``// Increment the count``          ``count++;``        ``}``        ``else` `{` `          ``// If element is present``          ``// Remove the element``          ``// And add it at the end as it is``          ``// the most recent element``          ``v.RemoveAt(it);``          ``v.Add(pages[i]);``        ``}``      ``}` `      ``// Return total page faults``      ``return` `count;``    ``}` `    ``/* Driver program to test pageFaults function*/``    ``static` `void` `Main(``string``[] args)``    ``{` `      ``int``[] pages = { 1, 2, 1, 4, 2, 3, 5 };``      ``int` `n = 7, c = 3;` `      ``Console.WriteLine(``"Page Faults = "``                        ``+ pageFaults(n, c, pages));``    ``}``  ``}``}`

Javascript

 `function` `pageFaults(n, c, pages) {``    ``// Initialize count to 0``    ``let count = 0;` `    ``// To store elements in memory of size c``    ``let memory = [];``    ``for` `(let i = 0; i < n; i++) {` `        ``// Find if element is present in memory or not``        ``let index = memory.indexOf(pages[i]);` `        ``// If element is not present``        ``if` `(index === -1) {` `            ``// If memory is full``            ``if` `(memory.length === c) {` `                ``// Remove the first element``                ``// As it is least recently used``                ``memory.shift();``            ``}` `            ``// Add the recent element into memory``            ``memory.push(pages[i]);` `            ``// Increment the count``            ``count++;``        ``} ``else` `{` `            ``// If element is present``            ``// Remove the element``            ``// And add it at the end as it is``            ``// the most recent element``            ``memory.splice(index, 1);``            ``memory.push(pages[i]);``        ``}``    ``}` `    ``// Return total page faults``    ``return` `count;``}` `let pages = [1, 2, 1, 4, 2, 3, 5];``let n = 7;``let c = 3;``console.log(`Page Faults = \${pageFaults(n, c, pages)}`);` `// This code is contributed by ishankhandelwals.`

Output
```Page Faults = 5

```

Output :

`Page Faults = 5`

Time Complexity: O(N*C)
Auxiliary Space:  O(C)

Approach using Doubly Linked List and Maps

We can use an unordered map and a doubly linked list to solve this problem efficiently. This is done by maintaining a map of nodes in memory. For each recently used node we can push it at the back of our doubly linked list, it consumes O(1) time. Searching in the map also takes O(1) time (NO HASH COLLISIONS ASSUMED). When we hit full capacity in memory, shift the head of the linked list and erase its occurrence from the map. This also can be done in O(1) time. Thus, giving the algorithm a runtime of O(N) in the worst case.

Follow the following steps to implement the idea

1) Construct the structure of the node of the doubly linked list. This contains data, previous and next pointers.

2) Start iterating in the array/stream of inputs. If the data is already in the map, this means its in memory. Find the pointer which is against the data and place it at the end of the linked list, signifying it was recently accessed with necessary linkages.

3) If the data is not in the map, place it at the end of the linked list with necessary linkages. And insert the data in the map with its node pointer. Also increment the page fault, since its not in the memory

4) Return the number of page faults.

C++

 `// Author: RainX (ABHIJIT ROY, NIT AGARTALA)` `#include ``using` `namespace` `std;` `struct` `Node {``    ``int` `data;``    ``Node* next = nullptr;``    ``Node* prev = nullptr;``    ``Node(``int` `data) { ``      ``this``->data = data; ``    ``}``};` `unordered_map<``int``, Node*> mpp;``int` `size = 0;``Node* head = nullptr;``Node* tail = nullptr;` `int` `pageFaults(``int` `N, ``int` `C, ``int` `pages[]) {``    ``int` `faults = 0;``    ``for` `(``int` `i = 0; i < N; i++) {``        ``if` `(mpp.find(pages[i]) == mpp.end()) {  ``// O(1) ``            ``faults++;``            ``if` `(size == C) {``                ``mpp.erase(head->data);``                ``head = head->next;``                ``size--;``            ``}``            ``Node* newNode = ``new` `Node(pages[i]);``            ``if` `(head == nullptr) {``                ``head = newNode;``                ``tail = head;``            ``}``          ` `            ``newNode->prev = tail;``            ``tail->next = newNode;``            ``tail = tail->next;``          ` `            ``size++;``            ``mpp[pages[i]] = newNode;``        ``}``        ``else` `{``            ``Node* ptr = mpp[pages[i]];``            ``if` `(ptr == head) {   ``// O(1) linkage time``                ``head = head->next;``                ``ptr->prev = tail;``                ``tail->next = ptr;``                ``tail = tail->next;``            ``}``            ``else` `if` `(tail != ptr) {  ``// O(1) linkage time``                ``ptr->prev->next = ptr->next;``                ``ptr->next->prev = ptr->prev;``                ``ptr->prev = tail;``                ``tail->next = ptr;``                ``tail = tail->next;``            ``}``        ``}``    ``}``    ``return` `faults;``}` `int` `main(){` `    ``int` `pages[] = { 1, 2, 1, 4, 2, 3, 5 };``    ``int` `n = 7, c = 3;` `    ``cout << ``"Page Faults = "` `<< pageFaults(n, c, pages);``    ``return` `0;``}` `// Author: RainX (ABHIJIT ROY, NIT AGARTALA)`

Java

 `import` `java.util.HashMap;``import` `java.util.Map;` `class` `Node {``    ``int` `data;``    ``Node next = ``null``;``    ``Node prev = ``null``;` `    ``public` `Node(``int` `data) {``        ``this``.data = data;``    ``}``}` `public` `class` `OptimalPageReplacement {``    ``static` `Map mpp = ``new` `HashMap<>();``    ``static` `int` `size = ``0``;``    ``static` `Node head = ``null``;``    ``static` `Node tail = ``null``;` `    ``static` `int` `pageFaults(``int` `N, ``int` `C, ``int``[] pages) {``        ``int` `faults = ``0``;` `        ``for` `(``int` `i = ``0``; i < N; i++) {``            ``if` `(!mpp.containsKey(pages[i])) {``                ``faults++;` `                ``if` `(size == C) {``                    ``mpp.remove(head.data);``                    ``head = head.next;``                    ``size--;``                ``}` `                ``Node newNode = ``new` `Node(pages[i]);` `                ``if` `(head == ``null``) {``                    ``head = newNode;``                    ``tail = head;``                ``}` `                ``newNode.prev = tail;``                ``tail.next = newNode;``                ``tail = tail.next;` `                ``size++;``                ``mpp.put(pages[i], newNode);``            ``} ``else` `{``                ``Node ptr = mpp.get(pages[i]);` `                ``if` `(ptr == head) {``                    ``head = head.next;``                    ``ptr.prev = tail;``                    ``tail.next = ptr;``                    ``tail = tail.next;``                ``} ``else` `if` `(tail != ptr) {``                    ``ptr.prev.next = ptr.next;``                    ``ptr.next.prev = ptr.prev;``                    ``ptr.prev = tail;``                    ``tail.next = ptr;``                    ``tail = tail.next;``                ``}``            ``}``        ``}``        ``return` `faults;``    ``}` `    ``public` `static` `void` `main(String[] args) {``        ``int``[] pages = {``1``, ``2``, ``1``, ``4``, ``2``, ``3``, ``5``};``        ``int` `n = ``7``, c = ``3``;` `        ``System.out.println(``"Page Faults = "` `+ pageFaults(n, c, pages));``    ``}``}`

Python3

 `class` `Node:``    ``def` `__init__(``self``, data):``        ``# Node constructor to initialize data, next, and prev attributes``        ``self``.data ``=` `data``        ``self``.``next` `=` `None``        ``self``.prev ``=` `None` `def` `page_faults(N, C, pages):``    ``size ``=` `0`  `# Initialize size as a local variable``    ``head ``=` `None``    ``tail ``=` `None``    ``faults ``=` `0``    ``mpp ``=` `{}  ``# Dictionary to store page number as key and corresponding Node as value` `    ``for` `i ``in` `range``(N):``        ``if` `pages[i] ``not` `in` `mpp:``            ``# Page fault: Page is not in memory``            ``faults ``+``=` `1` `            ``if` `size ``=``=` `C:``                ``# Memory is full, remove the least recently used page (head)``                ``del` `mpp[head.data]``                ``head ``=` `head.``next``                ``size ``-``=` `1` `            ``# Create a new Node for the current page and add it to the end of the linked list``            ``new_node ``=` `Node(pages[i])``            ``if` `head ``is` `None``:``                ``# If the list is empty, set the new node as both head and tail``                ``head ``=` `new_node``                ``tail ``=` `head` `            ``new_node.prev ``=` `tail``            ``tail.``next` `=` `new_node``            ``tail ``=` `tail.``next` `            ``size ``+``=` `1``            ``mpp[pages[i]] ``=` `new_node  ``# Update the dictionary with the new node``        ``else``:``            ``# Page is already in memory, update its position in the linked list``            ``ptr ``=` `mpp[pages[i]]``            ``if` `ptr ``=``=` `head:``                ``# If the page is the head, move it to the tail``                ``head ``=` `head.``next``                ``ptr.prev ``=` `tail``                ``tail.``next` `=` `ptr``                ``tail ``=` `tail.``next``            ``elif` `tail !``=` `ptr:``                ``# If the page is not the tail, adjust its position in the linked list``                ``ptr.prev.``next` `=` `ptr.``next``                ``ptr.``next``.prev ``=` `ptr.prev``                ``ptr.prev ``=` `tail``                ``tail.``next` `=` `ptr``                ``tail ``=` `tail.``next` `    ``return` `faults` `if` `__name__ ``=``=` `"__main__"``:``    ``pages ``=` `[``1``, ``2``, ``1``, ``4``, ``2``, ``3``, ``5``]``    ``n ``=` `7``    ``c ``=` `3` `    ``print``(``"Page Faults ="``, page_faults(n, c, pages))`

C#

 `using` `System;``using` `System.Collections.Generic;` `class` `LRUCache``{``    ``class` `Node``    ``{``        ``public` `int` `Data;``        ``public` `Node Next = ``null``;``        ``public` `Node Prev = ``null``;` `        ``public` `Node(``int` `data)``        ``{``            ``Data = data;``        ``}``    ``}` `    ``// Dictionary to store mapping of page number to corresponding node in the cache``    ``static` `Dictionary<``int``, Node> cacheMap = ``new` `Dictionary<``int``, Node>();``    ` `    ``// Variables to track the size, head, and tail of the cache``    ``static` `int` `size = 0;``    ``static` `Node head = ``null``;``    ``static` `Node tail = ``null``;` `    ``// Function to simulate page faults and return the total number of faults``    ``static` `int` `PageFaults(``int` `N, ``int` `C, ``int``[] pages)``    ``{``        ``int` `faults = 0;` `        ``// Iterate through the page references``        ``for` `(``int` `i = 0; i < N; i++)``        ``{``            ``// Check if the page is not in the cache``            ``if` `(!cacheMap.ContainsKey(pages[i]))``            ``{``                ``faults++;` `                ``// If the cache is full, remove the least recently used page (head)``                ``if` `(size == C)``                ``{``                    ``cacheMap.Remove(head.Data);``                    ``head = head.Next;``                    ``size--;``                ``}` `                ``// Create a new node for the current page``                ``Node newNode = ``new` `Node(pages[i]);``                ` `                ``// If the cache is empty, set both head and tail to the new node``                ``if` `(head == ``null``)``                ``{``                    ``head = newNode;``                    ``tail = head;``                ``}` `                ``// Add the new node to the end of the cache``                ``newNode.Prev = tail;``                ``tail.Next = newNode;``                ``tail = tail.Next;` `                ``// Update cache size and mapping``                ``size++;``                ``cacheMap[pages[i]] = newNode;``            ``}``            ``else``            ``{``                ``// If the page is already in the cache, move it to the end (most recently used)``                ``Node ptr = cacheMap[pages[i]];` `                ``if` `(ptr == head)``                ``{``                    ``head = head.Next;``                    ``ptr.Prev = tail;``                    ``tail.Next = ptr;``                    ``tail = tail.Next;``                ``}``                ``else` `if` `(tail != ptr)``                ``{``                    ``ptr.Prev.Next = ptr.Next;``                    ``ptr.Next.Prev = ptr.Prev;``                    ``ptr.Prev = tail;``                    ``tail.Next = ptr;``                    ``tail = tail.Next;``                ``}``            ``}``        ``}` `        ``return` `faults;``    ``}` `    ``static` `void` `Main()``    ``{``        ``// Example page references and cache size``        ``int``[] pages = { 1, 2, 1, 4, 2, 3, 5 };``        ``int` `n = 7, c = 3;` `        ``// Display the total number of page faults``        ``Console.WriteLine(``"Page Faults = "` `+ PageFaults(n, c, pages));``    ``}``}`

Javascript

 `// Equivalent JavaScript code with comments` `// Node class to represent elements in the linked list``class Node {``    ``constructor(data) {``        ``this``.data = data;``        ``this``.next = ``null``;``        ``this``.prev = ``null``;``    ``}``}` `// Map to store page numbers and corresponding nodes in the linked list``const mpp = ``new` `Map();``let size = 0; ``// Current size of the linked list``let head = ``null``; ``// Head of the linked list``let tail = ``null``; ``// Tail of the linked list` `// Function to simulate page faults and return the total faults``function` `pageFaults(N, C, pages) {``    ``let faults = 0; ``// Counter for page faults` `    ``for` `(let i = 0; i < N; i++) {``        ``if` `(!mpp.has(pages[i])) {``            ``faults++;` `            ``if` `(size === C) {``                ``// Remove the oldest page if the cache is full``                ``mpp.``delete``(head.data);``                ``head = head.next;``                ``size--;``            ``}` `            ``const newNode = ``new` `Node(pages[i]);` `            ``if` `(head === ``null``) {``                ``// If the linked list is empty, set the new node as both head and tail``                ``head = newNode;``                ``tail = head;``            ``}` `            ``newNode.prev = tail;``            ``tail.next = newNode;``            ``tail = tail.next;` `            ``size++;``            ``mpp.set(pages[i], newNode);``        ``} ``else` `{``            ``const ptr = mpp.get(pages[i]);` `            ``if` `(ptr === head) {``                ``// If the accessed page is the head, update the head and tail accordingly``                ``head = head.next;``                ``ptr.prev = tail;``                ``tail.next = ptr;``                ``tail = tail.next;``            ``} ``else` `if` `(tail !== ptr) {``                ``// If the accessed page is in the middle, adjust pointers to maintain order``                ``ptr.prev.next = ptr.next;``                ``ptr.next.prev = ptr.prev;``                ``ptr.prev = tail;``                ``tail.next = ptr;``                ``tail = tail.next;``            ``}``        ``}``    ``}` `    ``return` `faults;``}` `// Sample pages and cache size``const pages = [1, 2, 1, 4, 2, 3, 5];``const n = 7, c = 3;` `// Output the total page faults``console.log(``"Page Faults ="``, pageFaults(n, c, pages));`

Output
```Page Faults = 5

```
• Time Complexity: O(N)