Page replacement algorithms are essential components of virtual memory management in operating systems. When a page fault occurs and all memory frames are in use, the operating system must decide which page to evict to make room for the new page.
The goal of these algorithms is to minimize the number of page faults and maximize memory utilization, thus improving system performance.
Theory: The First-In-First-Out algorithm replaces the page that has been in memory for the longest time. It operates on the principle that older pages are less likely to be used again.
function FIFO(referenceString, frameCount) {
// Initialize variables
let frames = new Array(frameCount).fill(-1); // -1 indicates empty frame
let queue = []; // Queue to track order of pages loaded into memory
let pageFaults = 0;
// Process each page in the reference string
for (let page of referenceString) {
// Check if page is already in memory (page hit)
if (frames.includes(page)) {
// Page hit - no action needed in FIFO
continue;
}
// Page fault occurred
pageFaults++;
if (queue.length < frameCount) {
// If we have empty frames, use them
frames[queue.length] = page;
queue.push(page);
} else {
// Replace the oldest page (first in the queue)
let oldestPage = queue.shift(); // Remove the oldest page from queue
let index = frames.indexOf(oldestPage);
frames[index] = page; // Replace oldest page with new page
queue.push(page); // Add new page to end of queue
}
}
return pageFaults;
}
Time Complexity: O(1) for page replacement operation
Space Complexity: O(n) where n is the number of frames
Theory: The Least Recently Used algorithm replaces the page that hasn't been accessed for the longest period of time. It's based on the principle of temporal locality - recently used pages are likely to be used again soon.
function LRU(referenceString, frameCount) {
// Initialize variables
let frames = new Array(frameCount).fill(-1); // -1 indicates empty frame
let usageHistory = []; // Tracks order of page usage (most recently used at the end)
let pageFaults = 0;
// Process each page in the reference string
for (let page of referenceString) {
// Check if page is already in memory (page hit)
if (frames.includes(page)) {
// Page hit - update usage history (move page to end of history)
usageHistory = usageHistory.filter(p => p !== page);
usageHistory.push(page);
continue;
}
// Page fault occurred
pageFaults++;
if (usageHistory.length < frameCount) {
// If we have empty frames, use them
frames[usageHistory.length] = page;
usageHistory.push(page);
} else {
// Replace the least recently used page
let lruPage = usageHistory.shift(); // Get least recently used page
let index = frames.indexOf(lruPage);
frames[index] = page; // Replace LRU page with new page
usageHistory.push(page); // Add new page as most recently used
}
}
return pageFaults;
}
Time Complexity: O(n) for finding least recently used page (can be optimized to O(1) with proper data structures)
Space Complexity: O(n) where n is the number of frames
Theory: The Least Frequently Used algorithm replaces the page with the lowest reference frequency. If there's a tie, it usually selects the least recently used page among those with the lowest frequency.
function LFU(referenceString, frameCount) {
// Initialize variables
let frames = new Array(frameCount).fill(-1); // -1 indicates empty frame
let frequencies = {}; // Maps page → frequency count
let timestamps = {}; // Maps page → timestamp (for tie-breaking)
let pageFaults = 0;
let time = 0;
// Process each page in the reference string
for (let page of referenceString) {
time++; // Increment timestamp
// Initialize or update frequency counter and timestamp
frequencies[page] = (frequencies[page] || 0) + 1;
timestamps[page] = time;
// Check if page is already in memory (page hit)
if (frames.includes(page)) {
// Page hit - frequency already updated
continue;
}
// Page fault occurred
pageFaults++;
// If we have empty frames, use them
let emptyIndex = frames.indexOf(-1);
if (emptyIndex !== -1) {
frames[emptyIndex] = page;
continue;
}
// Need to replace a page - find the least frequently used
let minFrequency = Infinity;
let oldestTimestamp = Infinity;
let replaceIndex = 0;
for (let i = 0; i < frameCount; i++) {
let currentPage = frames[i];
let frequency = frequencies[currentPage];
let timestamp = timestamps[currentPage];
// Find page with lowest frequency, breaking ties with oldest timestamp
if (frequency < minFrequency ||
(frequency === minFrequency && timestamp < oldestTimestamp)) {
minFrequency = frequency;
oldestTimestamp = timestamp;
replaceIndex = i;
}
}
// Replace the selected page
frames[replaceIndex] = page;
}
return pageFaults;
}
Time Complexity: O(n) for finding least frequently used page
Space Complexity: O(m) where m is the number of unique pages in reference string
Theory: The Optimal algorithm replaces the page that won't be used for the longest time in the future. It requires knowing the future page reference pattern, which is impossible in real systems, making it theoretical.
function Optimal(referenceString, frameCount) {
// Initialize variables
let frames = new Array(frameCount).fill(-1); // -1 indicates empty frame
let pageFaults = 0;
// Process each page in the reference string
for (let currentIndex = 0; currentIndex < referenceString.length; currentIndex++) {
let page = referenceString[currentIndex];
// Check if page is already in memory (page hit)
if (frames.includes(page)) {
// Page hit - no action needed
continue;
}
// Page fault occurred
pageFaults++;
// If we have empty frames, use them
let emptyIndex = frames.indexOf(-1);
if (emptyIndex !== -1) {
frames[emptyIndex] = page;
continue;
}
// Need to replace a page - find the one that won't be used for the longest time
let farthestUseIndex = -1;
let replaceIndex = 0;
for (let i = 0; i < frameCount; i++) {
let currentPage = frames[i];
// Find the next use of this page in the reference string
let nextUse = -1;
for (let j = currentIndex + 1; j < referenceString.length; j++) {
if (referenceString[j] === currentPage) {
nextUse = j;
break;
}
}
// If this page won't be used again, replace it immediately
if (nextUse === -1) {
replaceIndex = i;
break;
}
// If this page will be used later than the current farthest, update
if (nextUse > farthestUseIndex) {
farthestUseIndex = nextUse;
replaceIndex = i;
}
}
// Replace the selected page
frames[replaceIndex] = page;
}
return pageFaults;
}
Time Complexity: O(n²) where n is the length of reference string
Space Complexity: O(n) where n is the number of frames
Note: The Optimal algorithm is also known as Belady's Optimal algorithm or OPT.
Theory: The Random algorithm simply selects a random page to replace when a page fault occurs and all frames are full. It makes no assumptions about future page references.
function Random(referenceString, frameCount) {
// Initialize variables
let frames = new Array(frameCount).fill(-1); // -1 indicates empty frame
let pageFaults = 0;
// Process each page in the reference string
for (let page of referenceString) {
// Check if page is already in memory (page hit)
if (frames.includes(page)) {
// Page hit - no action needed
continue;
}
// Page fault occurred
pageFaults++;
// If we have empty frames, use them
let emptyIndex = frames.indexOf(-1);
if (emptyIndex !== -1) {
frames[emptyIndex] = page;
continue;
}
// Choose a random frame to replace
let randomIndex = Math.floor(Math.random() * frameCount);
frames[randomIndex] = page;
}
return pageFaults;
}
Time Complexity: O(1) for page replacement
Space Complexity: O(n) where n is the number of frames
Algorithm | Time Complexity | Space Complexity | Belady's Anomaly | Implementation Difficulty | Performance |
---|---|---|---|---|---|
FIFO | O(1) | O(n) | Yes | Easy | Fair |
LRU | O(1) with optimized structures | O(n) | No | Moderate | Good |
LFU | O(n) or O(log n) with heap | O(m) | No | Moderate to Hard | Good |
Optimal | O(n²) | O(n) | No | N/A (Theoretical) | Best |
Random | O(1) | O(n) | Probabilistic | Very Easy | Unpredictable |
Note: In the above table, 'n' refers to the number of frames and 'm' refers to the number of unique pages in the reference string.