From Transistor to Browser

The Software · Chapter 9.c
How does each program get its own memory?

Updated Oct 12, 2026
Summarize
Transcript

How does each program get its own memory? Two programs both write to address three. Both expect their own value back.

I figured each program is built to use different addresses. But run the same app twice, and both copies use address three.

So every address is split in two: a page, and an offset inside it. Address three is page zero, offset three. Each program gets its own page table. A's table says page zero lives in frame five. Keep the offset: frame five, offset three, is cell eighty-three. The offset never changes; only the page is swapped for a frame. B's table sends page zero to frame eight instead. Same address three, two tables, two different cells.

So each gets its own memory through its own table! Two programs can use the same address without ever meeting.

Slide an address below across a page boundary, and watch where each program's copy lands.

The hosts' voices are synthetic, made with Breeze TTS 2 by BreezeBlue.

  1. The browser
  2. The network
  3. Software and languages
  4. The CPU
  5. Memory
  6. Arithmetic
  7. Logic gates
  8. The switch
Figure 9.c.1: Where we are in the climb from transistor to browser: on the software rung. This chapter models the address translation used to give programs separate views of memory.

The operating system runs many programs, each as a process in the sense of Chapter 9, on the one memory of Chapter 4, and each must believe that memory is its own. If they all used real addresses, two programs that both wanted address 3 would collide, and a careless or hostile one could read or overwrite another’s data. The fix is a layer of translation called virtual memory. Each program uses virtual addresses, numbered from zero as if it had the machine to itself. Every access passes through a page table that maps the program’s virtual pages to the physical frames it may access. In this example the two programs get disjoint frames. Real systems can also map a frame into several processes intentionally, for example to share data or read-only code.

Protection requires more than the translation formula. The operating system must control the tables, and user code must be unable to edit them or bypass the translation. Our Python functions trust the table and memory passed by the caller; they demonstrate mappings under those assumptions, not an enforced security boundary. Real page-table entries also carry access permissions.

9.c.1 Translation

A virtual address splits into two parts: a page number and an offset within that page. The page table turns the page number into a frame number; the offset rides through untouched. Figure 9.c.2 translates one address.

translationtranslation
Figure 9.c.2: Translating a virtual address. The address splits into a page and an offset; the page table maps the page to a frame; the offset passes through unchanged. Page 0, offset 3 through this table becomes frame 5, offset 3, which is physical address 83.

The interactive version needs the in-browser runtime.

Example 9.c-1. Translating through a page table

def translate(page_table: dict, virtual: int) -> int:
    """Translate a virtual address to a physical one through a page table. The
    page number selects a frame; the offset within the page is unchanged."""
    page, offset = divmod(virtual, PAGE_SIZE)1
    if page not in page_table:
        raise PageFault(f"virtual page {page} is not mapped")2
    frame = page_table[page]
    return frame * PAGE_SIZE + offset3

A real page fault can report a forbidden access, but it can also ask the kernel to complete valid work: allocate a page lazily, make a private copy before a write, or restore data moved to storage. The handler decides whether to supply a mapping and resume execution or reject the access. This model simply raises an exception for an absent entry.

9.c.2 Isolation

With trusted tables that map to disjoint frames, two programs can use the very same virtual address without meeting. This is the address-space mapping discussed in Chapter 9: a real context switch can select another table without copying memory. Our translator is separate from that chapter’s scheduler, which switches whole memory-list references. Figure 9.c.3 gives both programs virtual address 3; one table sends it to frame 5, the other to frame 8, so the two writes land in different physical cells.

isolationisolation
Figure 9.c.3: Two programs, one address, no collision. Program A and program B both write virtual address 3, but their page tables map it to different frames, so A’s value sits at physical 83 and B’s at physical 131. Through these fixed, disjoint mappings, each reaches only its own cells.

9.c.3 Virtual memory, run

Running ftb.vm gives two programs page tables that map their pages to different frames, has both write to virtual address 3, and shows where each lands.

output · ftb.vm
page size 16 cells
program A's table: {0: 5, 1: 2}
program B's table: {0: 8, 1: 9}

both programs write to virtual address 3:
  A's 3 -> physical 83
  B's 3 -> physical 131

A reads back 42, B reads back 99
Same virtual address, different memory: neither touched the other.

Both programs wrote to what each called address 3, yet A’s value went to physical 83 and B’s to physical 131, and each read back exactly its own. The page table makes that separation possible under the stated assumptions. If the Python caller changes A’s page 0 mapping from frame 5 to frame 8, A can read B’s 99; translation alone does not stop that change. In a real process, heap allocations live inside its virtual pages: the allocator hands out address ranges, and the table decides where they land. Our allocator and translator illustrate those two jobs separately.

The next chapter turns from memory that vanishes with the power to storage that does not: files.

Exercises