Lecture 13: Managing physical memory

First strawman: one big address space

Could just stick all processes into physical memory; allocate each process a block of addresses that it uses. When loading a program, use the linker to relocate all addresses so they are within the process's allocated space

Second strawman: simple MMU with base and bounds

Suppose we add some simple hardware: a memory management unit (MMU) is a piece of hardware that sits between the processor and the bus. When the processor accesses an address (by loading or storing for example), the MMU transforms the address before sending the request on the bus.

Terminology: the MMU performs address translation by mapping the logical addresses (also called virtual addresses) to physical addresses.

We can use a simple MMU to deal with some of the memory allocation problems discussed above. If we allocate a range of addresses to a process (lets say 0x1000 of them), we can use the MMU to translate 0x0 to the bottom of the address space, and 0xFFF to the top of the address space.

To do this, we can store two registers in the MMU: base and bounds. The MMU will take a virtual address, add the base register to find the physical address. It can also compare the physical address to the bounds register, and raise an exception if the address is out of range.

The base and bounds registers are set by the OS before context switching to the application.

For example, if P1 is given physical addresses 0x100000 -- 0x105000, then when P1 is scheduled, we set the base and bounds registers to 0x100000 and 0x105000 respectively. If process P1 accesses (virtual) address 0x25FC, the MMU will translate this to 0x1025FC. If P1 tries to access address 0x5500, then the MMU will translate this to 0x105500, but since this is bigger than the bounds register, the MMU will cause an exception, allowing the OS to crash the program.

Note that each process will have its own base and bounds; this information will be stored in the process's PCB (this is the "VM info" we alluded to earlier).

With this simple address translation, we have isolation, and processes do not know where they are located. We still have problems with both internal and external fragmentation.

Swapping

It may seem like we can only run as many processes as we have physical memory to store, but in fact if we have a backing store, we can swap processes out to disk.

If a new process arrives and there is insufficient space to allocate for it, we can take an existing process and swap it out: move the entire contents of its address space to disk. We can then reclaim its space to allocate to the new process. Later, when that process is scheduled, we can swap it in: move it from the disk back into a region of physical memory.

Because processes do not have any information about their physical addresses, we don't have to swap a process back into the same physical location that we swapped it out of. We simply need to update the base and bounds registers in its PCB.

Note however that swapping is extremely slow: any communication with disk is expensive; copying an entire address space is downright painful. But, if the user wants to run more processes than they have ram, there isn't much choice (but see paging below).

Paging

Paging solves many of the remaining problems discussed above. The idea behind paging is that we split a process's logical address space into many small chunks called pages. Pages are typically on the order of a few kilobytes.

In addition, we divide up the physical address space into frames. We are allowed to place any page into any frame.

The terminology can be useful as a guide to understanding what's going on. Think of pages as numbered pages in a three-ring binder. A process (binder) contains a large number of pages. On your desk (physical memory), you have a small number of picture frames. In order to read a page, you must take it out of the binder and place it in a frame.

The advantages of this scheme are many:

To accomplish paging, we need a more complicated MMU. The MMU must do the following to translate a virtual address:

For example, suppose the page size is 4kb (0x1000b), and the contents of physical memory are:

frame # physical address frame contents
0x0 0x0000 Process 3, page 0x85
0x1 0x1000 Process 2, page 0x02
0x2 0x2000 Process 3, page 0x14
0x3 0x3000 Process 1, page 0x01

Suppose process 3 accesses (virtual) address 0x14303. This address refers to the 0x303rd byte of the 0x14th page of process 3's address space (the offset is 0x303, and the page number is 0x14). The MMU will find that process 3's page 0x14 is mapped into frame 0x2 (which always starts at physical address 0x2000). Therefore, the physical address that it outputs is the 0x303rd byte of the 0x2nd frame, or 0x2303.

The mysterious part of this process is how the MMU knows which page is in which frame. This data is stored in memory in a lookup data structure, called the page table. We will discuss page tables in more detail tomorrow.