Chapter 9. Memory Management

This chapter covers the allocation, manipulation, and eventual release of memory.

The Process Address Space

Linux virtualizes its physical resource of memory. Processes do not directly address physical memory. Instead, the kernel associates each process with a unique virtual address space:

Pages and Paging

For the purposes of memory management, the page is the most important of these: it is the smallest addressable unit of memory that the memory management unit (MMU) can manage. Thus the virtual address space is carved up into pages. The machine architecture determines the page size. Typical sizes include 4 KB for 32-bit systems and 8 KB for 64-bit systems.

A 32-bit address space contains roughly a million 4 KB pages; a 64-bit address space with 8 KB pages contains several magnitudes more. A process cannot necessarily access all of those pages (they may not correspond to anything). Thus, pages are either valid or invalid:

Page fault, paging in and paging out *

If a valid page is associated with data on secondary storage, a process cannot access that page until the data is brought into physical memory. When a process attempts to access such a page, the memory management unit generates a page fault. The kernel then intervenes, transparently paging in the data from secondary storage to physical memory.

Because there is considerably more virtual memory than physical memory, the kernel may have to move data out of memory to make room for the data paging in. Paging out is the process of moving data from physical memory to secondary storage. To minimize subsequent page-ins, the kernel attempts to page out the data that is the least likely to be used in the near future.

Sharing and copy-on-write

Multiple pages of virtual memory, even in different virtual address spaces owned by different processes, may map to a single physical page. This allows different virtual address spaces to share the data in physical memory. For example, many processes on the system are using the standard C library. With shared memory, each of these processes may map the library into their virtual address space, but only one copy need exist in physical memory. As a more explicit example, two processes may both map into memory a large database. While both of these processes will have the database in their virtual address spaces, it will exist in RAM only once.

The shared data may be read-only, writable, or both readable and writable. When a process writes to a shared writable page, one of two things can happen. The simplest is that the kernel allows the write to occur, in which case all processes sharing the page can see the results of the write operation. Usually, allowing multiple processes to read from or write to a shared page requires some level of coordination and synchronization among the processes, but at the kernel level the write "just works" and all processes sharing the data instantly see the modifications.

Alternatively, the MMU can intercept the write operation and raise an exception; the kernel, in response, will transparently create a new copy of the page for the writing process, and allow the write to continue against the new page. We call this approach copy-on-write (COW). Effectively, processes are allowed read access to shared data, which saves space. But when a process wants to write to a shared page, it receives a unique copy of that page on the fly, thereby allowing the kernel to act as if the process always had its own private copy. As copy-on-write occurs on a page-by-page basis, with this technique a huge file may be efficiently shared among many processes, and the individual processes will receive unique physical pages only for those pages to which they themselves write.

Memory Regions

The kernel arranges pages into blocks that share certain properties (e.g. access permissions). These blocks are called mappings, memory areas, or memory regions. Certain types of memory regions can be found in every process:

Doubts and Solution

Verbatim

p295 on memory regions

The data segment, or heap, contains a process’s dynamic memory. This segment is writable and can grow or shrink in size. malloc() can satisfy memory requests from this segment.

data segment = heap ?