The page table could take up too much room (recall: 4MB / process)
There is a large gap in virtual space
The page table contains a lot of unused space
It doesn't actually allocate all of this memory, only uses empty indirect blocks
We can apply this concept to page tables:
x86: 2 level page table
Virtual Address: 10 bit high part, 10 bit low part, 12 bit offset
+------------------------+------------------------+----------------------+(unusual case in memory references)
Low-level memory allocation
mmap(lots of parameters) system call:
When try to access this, page fault, file is brought to this location
Can do I/O without reads or writes
Most common file to mmap is /dev/zero (reads all zeroes, writes ignored)
Can create new memory, initialized to zero
Bad design if there is an actual segfault (ok for Steve Bourne (maybe), not for the rest of us)
The kernel must deal with page faults
Page faults require read from and write to secondary storage (20-30 ms on hard disk)
We want to avoid page faults as much as possible
The removal policy is tricky, need to be careful which page to remove...
What is the best way to do I/O to disk?
B seems more simple, why not do it?
Policy: which page will be the victim?
If pages are accessed at random (the 'R' in "RAM" does stand for Random), then choose a page at random! However, the principle of locality of reference applies and we want to exploit this.
Assume 5 virtual pages (0-4), 3 physical pages (A-C)
Reference string is a sequence of virtual page #'s (VPNs)
0 | 1 | 2 | 3 | 0 | 1 | 4 | 0 | 1 | 2 | 3 | 4 |
empty entries are garbage
yellow highlighted entries are page faults
FIFO policy | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 0 | 1 | 4 | 0 | 1 | 2 | 3 | 4 | ||
A | 0 | 0 | 0 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 | |
B | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 2 | ||
C | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 3 | 3 | |||
9 faults |
What if we get another page of physical memory?
FIFO policy with another page of physical memory | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 0 | 1 | 4 | 0 | 1 | 2 | 3 | 4 | ||
A | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 3 | 3 | |
B | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 4 | ||
C | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | |||
D | 3 | 3 | 3 | 3 | 3 | 3 | 2 | 2 | 2 | ||||
10 faults! |
LRU (Least Recently Used) | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 0 | 1 | 4 | 0 | 1 | 2 | 3 | 4 | ||
A | 0 | 0 | 0 | 3 | 3 | 3 | 4 | 4 | 4 | 2 | 2 | 2 | |
B | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 3 | ||
C | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 4 | |||
10 faults! |
Note: In practice (not for this contrived example), LRU is better than FIFO
Optimal policy: consult an oracle and find the page least needed in the future | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 0 | 1 | 4 | 0 | 1 | 2 | 3 | 4 | ||
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 3 | 3 | |
B | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ||
C | 2 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 | |||
7 faults |
You can run the program, get reference string, and use this for the next execution.
More generally, get statistics from previous reference strings to approximate oracle.
Step 1 takes a long time, so instead:
Faster to copy one page than entire program
The dirty bit records for each page whether it has been modified since it was read in. If dirty bit is clear, no need to write out to disk. Some hardware does this for you. Otherwise, can do this in software.
When you bring a page in: