c++operating-systemheap-memorycpuvirtual-memory

How does the OS know what virtual page a specific memory address references?


I am trying to understand how variables allocated in programs (such as with the new keyword in C++) translate to virtual pages.

My understanding is that each process will have its own virtual memory space and this space will be segmented into several pages of a fixed size (such as 64 bytes). When we allocate memory in our program, we start at the first address and move downwards. So if we allocated 128 bytes, we would be consuming two pages, both of which would be slotted into the MMU page table.

The part that I'm having difficulty in understanding is the following:

  • If I dynamically allocated an integer in memory, I could potentially have a memory address that reads something like 0x78C75ABC
  • How does the OS know what corresponding virtual page this memory address corresponds to?

I am assuming that it basically runs a count from 0 -> memory address and divides that by the fixed page size (64 bytes). Then it can access the page table with this number.

I understand that a large portion of this would be system-dependent but I'm just trying to grasp a general understanding of it. Thanks!


Solution

  • As Peter Cordes pointed out in a comment, your question seems to have things kind of backwards.

    Disclaimer: details can and do vary somewhat depending on the OS and hardware you're using. So what I'm going to describe is one possible scenario, not necessarily exactly how your particular OS works.

    The OS starts out "owning" all the physical memory on the machine.

    When your program needs some memory, it allocates it from the OS. To satisfy that request, the OS will allocate some address space (but not necessarily any physical memory) to satisfy the request. To do that, it creates page table entries for as many pages as necessary to satisfy the request.

    Initially, it marks all those addresses as "valid", but also as "not present", meaning there's no physical memory to back them, so attempting to read or write any of those addresses will result in a processor exception.

    Then when your program tries to read or write inside that block of memory, a processor exception will be raised. The exception handler will look at the page table entry, but there's no physical memory attached to it, so it'll allocate some physical memory to back that address. It'll modify the page table entry to map that virtual address to whatever physical memory page it allocated. Finally, it'll return from the exception, so the instruction can finish executing.

    As far as how the mapping is done, you've described it reasonably accurately. The size of a page is normally a power of 2 (and usually quite a bit larger than 64 bytes--usually at least 4 kilobytes). Since the page size is a power of 2, we can easily break the virtual address into two pieces: the upper bits become the page number, and the lower bits (e.g., 12 least significant bits for a 4 kilobyte page size) are an offset into that page.

    So, the page table is basically an array of physical addresses that's indexed by page numbers (with a few other bits of data added, such as accessibility--whether this page is read/write or read-only, for example). When you use a virtual address, the processor splits the address into the bottom N bits and the upper M bits. It uses the upper M bits to look up a physical address in the page table, then adds on the bottom N bits as an offset into the page to get a complete physical address.