Page Eviction Algorithms

When a page fault occurs (data that is not in RAM needs to be loaded into RAM) and our RAM is full, we must decide on a page to evict from RAM to make room for the new page. There are several approaches to how we might want to evict pages.

Page Eviction Strategy #1: First In, First Out

The most basic strategy for evicting a page is simple: evict the page that has been in memory the longest. More generally, we call this a first in, first out or FIFO page eviction strategy.

To illustrate how this works, consider a series of page accesses:

Page Access: 1733401743899339917

At each step, we check if the page is already loaded into RAM. If the page is not already loaded into RAM, a page fault will occur and the data will be loaded into an available spot in RAM. If needed, the oldest page will be evicted.

  • Page 17 is requested and is not in RAM. A page fault occurs and its loaded into RAM[0]. (We will denote a page fault by making the square bold where is was loaded.)
Page Access: 1733401743899339917
RAM[0]: 17
RAM[1]:
RAM[2]:
RAM[3]:
  • Page 33 is requested and is not in RAM. A page fault occurs and its loaded into RAM[1].
Page Access: 1733401743899339917
RAM[0]: 1717
RAM[1]: 33
RAM[2]:
RAM[3]:
  • Page 40 is requested and is not in RAM. A page fault occurs and its loaded into RAM[2].
Page Access: 1733401743899339917
RAM[0]: 171717
RAM[1]: 3333
RAM[2]: 40
RAM[3]:
  • Page 17 is already in RAM and can be accessed without a page fault.
Page Access: 1733401743899339917
RAM[0]: 17171717
RAM[1]: 333333
RAM[2]: 4040
RAM[3]:
  • Page 43 is requested and is not in RAM. A page fault occurs and its loaded into RAM[3].
Page Access: 1733401743899339917
RAM[0]: 1717171717
RAM[1]: 33333333
RAM[2]: 404040
RAM[3]: 43
  • Page 8 is requested and is not in RAM. A page fault occurs and the oldest page is evicted – Page 17 is evicted from RAM[0] and replaced with Page 8.
Page Access: 1733401743899339917
RAM[0]: 17171717178
RAM[1]: 3333333333
RAM[2]: 40404040
RAM[3]: 4343
  • Page 99 is requested and is not in RAM. A page fault occurs and the oldest page is evicted – Page 33 is evicted from RAM[1] and replaced with Page 99.
Page Access: 1733401743899339917
RAM[0]: 171717171788
RAM[1]: 333333333399
RAM[2]: 4040404040
RAM[3]: 434343
  • Page 33 is requested and is not in RAM. (This is a really sad, as we just evicted Page 33!) Since it’s not in RAM, a page fault occurs and we evict the oldest page (Page 40) from RAM[2] and load in Page 33.
Page Access: 1733401743899339917
RAM[0]: 1717171717888
RAM[1]: 33333333339999
RAM[2]: 404040404033
RAM[3]: 43434343
  • Page 99 is already in RAM! :)
Page Access: 1733401743899339917
RAM[0]: 17171717178888
RAM[1]: 3333333333999999
RAM[2]: 40404040403333
RAM[3]: 4343434343
  • Finally, Page 17 is now a RAM and one final page fault occurs.
Page Access: 1733401743899339917
RAM[0]: 171717171788888
RAM[1]: 333333333399999999
RAM[2]: 4040404040333333
RAM[3]: 434343434317

Summary

After the ten page accesses, this is our full page table/RAM access diagram:

  • A page faults occurred when the cell is outlined in a bold,
  • A page access occurred when the cell is highlighted
Page Access: 1733401743899339917
RAM[0]: 171717171788888
RAM[1]: 333333333399999999
RAM[2]: 4040404040333333
RAM[3]: 434343434317

Analysis

When using the FIFO page eviction strategy, we saw we needed eight page faults when accessing the pages in this access pattern. Since a page fault is an expensive operation (loading 4 KiB of data from storage into RAM), our goal is to minimize the number of page faults.

Page Eviction Strategy #2: Least Recently Used (LRU)

Another second strategy to explore is to examine how recently page page was used (accessed) instead of simply how long the page has been in RAM. By doing this, a frequently used page should be able to stay in RAM for a long time as long as it’s continually used.

Using the same memory access sequence, we can fill in the table the same way:

Page Access: 1733401743899339917
RAM[0]: 17
RAM[1]:
RAM[2]:
RAM[3]:

[…after all of the accesses…]

Page Access: 1733401743899339917
RAM[0]: 17171717171717333333
RAM[1]: 3333333388888
RAM[2]: 4040404099999999
RAM[3]: 434343434317

Analysis

On this memory sequence, LRU resulted in a different layout of pages within RAM but still had 8 page faults. We would need to explore more samples, and longer access patterns, to understand if LRU would outperform FIFO on this system.

However, what’s the best we can do?

Page Eviction Strategy #3: Optimal (OPT)

As we explore more strategies, we should explore what the optimal scenario would look like. Consider what would be the optimal eviction strategy:

  • We want to evict the page that is used furthest in the future among all of the pages in RAM.
  • This requires us know the future (impossible in the real world!) but will provide us the ability to find the best-case solution.

Using the same memory access sequence, we can fill in the table the same way:

Page Access: 1733401743899339917
RAM[0]: 17
RAM[1]:
RAM[2]:
RAM[3]:

[…after all of the accesses…]

Page Access: 1733401743899339917
RAM[0]: 17171717171717171717
RAM[1]: 333333333333333333
RAM[2]: 4040408*99*999999
RAM[3]: 434343434343
*: When deciding which page to evict to load in Page 8 and Page 99, we could have used either RAM[2] or RAM[3] since pages stored in both RAM[2] and RAM[3] are never accessed again. I choose to use the earliest index in my tie-breaking.

Analysis

Using an optimal approach, we find we require six page faults even if we can know the future.

Page Eviction Strategy #4: Not Recently Used (NRU)

A new strategy we can explore begins to add more complexity. We want to capture the idea of how recently used is the page? To do that:

  • When a page is used (accessed), set the recentlyUsed bit to 1.
  • When a page needs to be evicted, evict a page least recently used page that has the recentlyUsed bit set to 0. If no pages have the recentlyUsed bit set to 0, set all pages recentlyUsed bit to 0 and evict the least recently used page.

Using the same memory access sequence, we can fill in the table the same way. Except that we will add an ! when the recentlyUsed bit is 0 and the page is in danger of being evicted:

Page Access: 1733401743899339917
RAM[0]: 17
RAM[1]:
RAM[2]:
RAM[3]:

[…after all of the accesses…]

Page Access: 1733401743899339917
RAM[0]: 171717171717 !17 !333333
RAM[1]: 3333333388888
RAM[2]: 40404040 !99999999
RAM[3]: 4343 !43 !43 !43 !17
!: Recently used bit is equal to zero.

Page Eviction Strategy #5: Least Frequently Used (LFU)

A final strategy we can explore captures the idea of how frequently used is the page?

In addition to storage the page, we will store the useCount. When evicting a page, we will evict the page with minimal value of useCount; in the case of a tie, we will evict the page that was least recently used:

Page Access: 1733401743899339917
RAM[0]: 17 (1)
RAM[1]:
RAM[2]:
RAM[3]:

[…after all of the accesses…]

Page Access: 1733401743899339917
RAM[0]: 17 (1)17 (1)17 (1)17 (2)17 (2)17 (2)17 (2)17 (2)17 (2)17 (3)
RAM[1]: 33 (1)33 (1)33 (1)33 (1)8 (1)8 (1)8 (1)8 (1)8 (1)
RAM[2]: 40 (1)40 (1)40 (1)40 (1)99 (1)99 (1)99 (2)99 (2)
RAM[3]: 43 (1)43 (1)43 (1)33 (1)33 (1)33 (1)
(x): Denotes the use count for the page in memory.
Next: Page Table Entry >>