Virtual Memory

Address Space

- Context for memory address

- Maps an address (a name for a memory location) to a slot in memory holding 1 byte of data

32 bit addresses Þ Bytes = 4 GB address space size

            Memory size Þ # memory chips in computer

            Physical Address Space

            - Mapping used by memory controller

             0 ® memory size Þ transistor

             > memory size maps to zero

            Virtual Memory Idea

Processes don’t use physical address space!

            - Each process has it’s own address space

            - Processor supports a virtual address space

            - Process’ address accessed are translated into physical addresses

            Page Map Function

                       

           

            VM Advantages

            + Flexible Allocation

            + Isolation

            + Illusion of very large memory

            + Performance

            “Any problem in CS can be solved with another layer of indirection” - David Wheeler

            Flexible Allocation

                        ptr = sys_alloc(size)                  

                        sys_free(ptr)

           

            - Example: No Virtual Memory

            Size = 4KB       (Fixed size allocation)

           

           

            Fragmentation: there is unused memory that cannot be allocated

            - Internal Fragmentation: chunk size > used memory e.g. 4KB > 1 byte

           

            Either

            ® sys_alloc succeeds are returns memory

            ® No one could allocate memory

            - Example: Variable size allocation

            Concept: size any number of bytes

            Steps:

            1) sys_alloc(1024) ® maps to address 0

            2) sys_alloc(3 MB) ® maps to address 1024

            3) sys_alloc(4 MB) ® fails (not enough memory)

            4) sys_free(0)

            5) sys_alloc(1MB) ® fails (not enough memory in a continuous block)

           

           

           

            External fragmentation: memory available but arranged poorly

            Solution: compaction!

            - Pointers invalidated

            - $$$ (performs poorly)

            - Virtual memory allocation

            Concept: page virtual memory

            Page = continuous chunk of memory, size defined by processor, aligned in size boundary

            X86: page size = 4KB

           

            Paged VM Works:

           

           

           

Variable Allocation with Paged Virtual Memory

sys_alloc(4096 bytes)
sys_alloc(3 MB)
sys_free(4096 bytes)
sys_alloc(1 MB)

Allocation has 2 pieces
1. Virtual address space
2. Physical Memory Mapping Virtual Addresses to Physical Addresses

Isolation
Goals:
1. Prevent processes from affecting one another
2. Process’ address spaces do not include other process’ memory

Implementation:
1. Add a current privilege level(CPL) to the page map function
B(Virtual address, Current Privilege Level) -> Physical address or Page fault

Fun fact 1- In x86 architecture the Kernel must be in every virtual address space to be able to handle interrupt jumps.

Fun fact 2- In x86 architecture, the 0 CPL is supervisor and 1, 2, and 3 are user levels.

Disadvantages and potential violations:

After putting on an evil hat, we thought of a few ways to violate the isolation goals.
1. Change CPL
2. Change B function
3. Using direct memory access (DMA) to read or write memory directly, bypassing the B function.

The solution to violations 1 and 2 is to have all the following changes require a CPL of 0
A. Installing a new B function
B. Changing the privilege level in a B function
C. Changing a physical address mapping in a B function

Fun fact 3 – In x86 architecture the lcr3(pagedirectory_t page) function is used to switch to a new address space

The solution to 3 is to produce a segmentation fault if memory that a user is not supposed to have access to is attempted to be read from or written to.

Alternate Design for Paged Virtual Memory

Paged virtual memory: Complex mapping of virtual memory to physical pages
Segmented Virtual Memory: Adds an offset to every address, but odes not solve external fragmentation

            Why virtual memory is great:

 

Benefits of mapped virtual memory: 

1. Allows processes whose aggregate memory requirement is greater than the amount of physical memory, as infrequently used pages can reside on the disk.

2. It also enforces separate memory spaces for different process, as the page map function will never even return a pointer to a physical page allocated to another process.

 

For example:

Virtual memory:

 

Process A:

|-AA--AAA---AAAAAA----AAAAAAAA------AA|  -> 21 pages

 

Process B:

|---B------BBBBBBBBBBBB----BBBBB------|  -> 19 pages

 

Process C:

|--CCCCC----CCC--CCCC---CCCCCCCC---C--|  -> 21 pages

 

Physical Memory:

|AACACBACABCBAACACBCABCABCABCABCABCABA|  -> 40 pages in physical memory

 

Memory swapped out to disk:

|ABCABCBABCBABCABCB……                    -> 21 pages swapped out to disk.

 

This works since many processes use way more memory than they actually need at a given time, so much of it can reside on the disk.

 

A great example of this is the windows word paperclip.  Do you really want to have 600 animated gifs to be loaded and stored in memory?

 

    Since most (all) of the time the dancing paper clip lies dormant, the pages that contain the images can reside on disk, and only be loaded when the virtual memory manager page faults.

 

Updated page fault handling sequence:

    So this changes our page fault sequence:

    Page fault!

    Check faulting address:

    If protection violation, isolation fault -> kill process.

    If fault on swapped memory, move a page from memory to disk then read the swapped memory into disk, and install the mapping.

 

Page Replacement algorithms

   

Not always simple:

    Belady's Anomaly: sometimes, by adding more memory you can actually incur MORE SWAPS.

    

    Furthest in the future.  Proven to be optimal, just very difficult to implement, as the memory manager cannot predict which pages will be needed in the future.

 

    First in First Out.  The problem is that often used pages may be swapped out too quickly.

    

    Least recently used. (best, remember how to implement)

    The usual, practical implementation: swap out the least recently used.

    Implementation:

    Start a process. Mark its address space as empty, so B-function will always give a page fault.  On a page fault, mark the page as recently used, then install a mapping. 

- For each page, keep track of an age "p_age", which is the number of "timer
interrupts" since the page was accessed.  (Time rinterrupts is in quotes
because you want to track only when the process is running.)
- On each timer interrupt, increment every page's p_age member, and mark all
pages as inaccessible.
- When a page fault happens, mark the page accessible and set the page's p_age
member to 0.

    

    However, we don’t bother to write have a dirty bit

    Hardware turns on it the page is written.

    Load the page, clear the dirty bit

    The B function has a third argument, write.  The dirty bit can be emulated by marking the page as read only.

    

    PF for a clean page -> mark dirty, allow writes.

    

    Generally this is cheaper, as programs read more than they write 

 

Using page mapping to improve performance

 

Some optimizations:

 

Don’t swap out clean pages to disk, they haven’t been changed.  Simply reload them.

    

    Marking pages as read only is powerful... for example, if a process forks, clean pages dont have to be recopied into the new memory space, as clean pages will of course be identical.  The page is shared until a write is called on the page, and then the page is copied and remapped to the duplicated process before the write, then mark the page as read only.  Note that this procedure still enforces memory isolation.

 

For example

 

Process A's memory space.  C means clean, D means dirty:

A:

|-----CCCC-----CCCC------CCCC-----CC-------|

A is using a total of 14 pages

 

Suppose a fork is called.  Immediately after the fork, the two processes have nearly identical memory spaces, so no physical memory needs to be copied yet, because the page map function can just map both processes to the same page.

 

A:

|-----CCCC-----CCCC------CCCC-----CC-------|

 

B:

|-----CCCC-----CCCC------CCCC-----CC-------|

Both processes combined still use 14 pages, since no memory has been changed yet.

 

However once a process writes to memory, the copy on write procedure is used, yielding:

 

A:

|-----CCCC-----CCCC------DDDD-----CC-------|

 

B:

|-----CCCC-----CCCC------DDDD-----CC-------|

The memory manager will then allocate 4 pages for process B.  Both processes now use only a total of 18 pages, instead of 28.