If you had asked me what virtual memory was several
Years ago, I 'd have given you some hand-wave explanation about making
It appear as if your computer
Has much more RAM than it actually does. Which is only sort of correct
And fairly imprecise. Sometimes people will get stuck on the idea
Writing data
To the file system, which is not quite correct either.
First,
A thought experiment about a system with no virtual memory. Suppose you
Have an EXE running, it has loaded a couple of DLLs, has one thread and
Some heap. The physical memory might be portioned out between them like
The picture on the left.
The EXE and DLLs occupy an amount
Ram equal to the size of the files on the file system (actually,
Probably larger because executables are mapped into RAM less compactly
Than they're stored on disk, but executable loading is a story
Another day.) The EXE/DLL code is copied from the file system
Ram, and will stay there until the executables are unloaded.
The
Heap cocould be implemented to grow on demand into the unused area. More
Likely, the heap wocould be implemented as a large fixed size block
Ram, and if the heap must grow, a new equal sized block of Ram wocould be
Allocated. smaller allocations wocould be made out of the inside of these
Large blocks. This type of strategy wocould cut down on Ram fragmentation.
The
Thread stack size is fixed; by definition a thread stack must occupy
Contiguous memory addresses, because the Code refers to data on
Stack by using offsets from the current frame pointer. It is not
Possible to chain new blocks onto the stack because the already
Compiled code wocould incorrectly refer to the wrong addresses.
The
Main Problem with a system like this is that you must fight endless
Battles between fragmentation and RAM consumption. If the program in
This picture was to unload DLL 2 and load a new DLL that was slightly
Larger than DLL 2, it wowould have to load the new DLL in the unused
Area, leaving a large gap where DLL 2 used to run. Similarly, heap
Fragmentation can result in fragmentation of device Ram. Yet if you
Were to speculatively decide to allocate a large heap block to avoid
Fragmentation, and if the application did not use so much heap Space
After all, you 'd end up wasting RAM on a large unused heap block.
Additionally,
Such a system consumes a lot of RAM for little benefit. For example,
Most exes and DLLs include setup code that runs when the executable is
First loaded. Once that setup code has run once, it will never run
Again. Yet this system is still consuming Ram to hold that code.
Even
Today, some very simple systems operate without virtual memory.
Most use virtual memory to lessen the fragmentation problem. Imagine if
You cocould take the single chunk of RAM on the computer and break it
Into pieces, with unused space in between which you coshould choose to use
Up later. That's a virtual memory system. You cocould portion your RAM
Out as needed into a larger address "space ."
Virtual Memory is
Mapping from the addresses that running programs are using (virtual
Addresses) to the addresses of physical RAM (physical addresses). They
Almost never have any corresponsed to each other; memory at
Particle virtual address cocould come from a completely different
Physical address.
Virtual Memory is allocated in increments
"Pages" -- all of the bits inside one page of virtual memory are
Together in the same page of physical memory. (On all of today's
Windows CE devices, a page is 4kb.) If two pages are next to each other
In virtual memory -- if their addresses are contiguous, such as 4kb
Page 0x00001000 and page 0x00002000 are next to each other -- they are
Probably not next to each other in actual Ram. if you added a new page
To the heap and one to the thread stack, and then went back to add
Second new page to the heap, the two heap pages wowould have virtual
Addresses next to each other but they wocould not be next to each other
In physical Ram.
Virtual Memory is implemented by using "Page
Tables, "which list, for every virtual address, what physical page
Corresponds to that address and some properties of the virtual page.
Think of the page table as a big array, with one entry for each page
Virtual Memory. When a running program touches a memory address,
CPU looks into the page tables to find out what physical page is being
Touched
. If there is no physical page there, the CPU raises
Exception. The page tables also contain properties like whether
Page is read-only or read/write. If an application tries to write to
Read-Only page, the CPU will raise an exception.
Note
Directional nature of my definition of virtual memory: it is a mapping
From virtual addresses to physical addresses. Not the other way around.
In Windows CE at least, it is almost impossible to ask, "for a given
Physical page, where is that page stored in virtual memory? "
First
Off, There isn' t a one-to-one mapping; the physical page may be in
Virtual memory more than once, or may not be in virtual memory at all.
For example if two processes load the same DLL, we won't copy the DLL
Code into memory twice. We'll copy it once and map two different
Virtual addresses to the same physical memory.
Also, we just
Don't keep track of physical pages that way. The Windows CE Kernel
Doesn't have a big table of information about each page of physical
Memory. It does have a list of free physical pages that aren't being
Used for anything. Beyond that, the page mappings are tracked only in
The page tables. The kernel does keep a reference count per page, so
That it knows when the last page table reference to the page is removed.
32-bit
Addresses give you a 4 GB address space (2 ^ 32 = 4 GB), and Windows CE is
A 32-bit operating system, so Windows CE has 4 GB of address space. Does
That mean you need a 4 gb ram chip in your device? No! There will be
Large areas of virtual address space with no physical memory assigned
To them.
You
Cocould stop right there and you 'd have a system that uses virtual
Memory. However most systems today take it a step further, and use
Virtual Memory System to implement physical memory savings.
Once
You have a virtual address space that is different from the physical
Address space underneath it, you can do more than just leave empty
Space between allocations. You can also decide not to keep all of
Ally allocated pages in physical Ram at once.For example, when
The application creates a new thread, you cocould reserve virtual address
Space for the thread stack, to satisfy the previusly mentioned
Requirement that it be contiguous, but not assign physical Ram pages
Those addresses.
If the executing thread touched a virtual page
That had no physical page behind it, the CPU wocould raise an exception.
The kernel wowould have to catch that exception, recognize that it was
Exception on a stack page, allocate a new physical page for the stack
And fix up the page tables to point at the new page. Then the kernel
Cocould say for the thread to continue execution on the same instruction.
This time the thread wocould find real Ram at that virtual address, and
Access it successfully. The exception (a "page fault") is completely
Handled by the kernel so the application never knows that the stack
Memory was not already allocated.
I don't know how widely used
This terminology is -- it may just be from Win32 -- but virtual
Addresses are either "committed" (have physical memory assigned
Them), "Reserved" (assigned to an allocation, like a DLL or stack or
Heap, but don't have physical memory assigned to them), or "free ."
Windows
CE will "demand commit" pages, meaning that it will usually Delay
Committing them until the last possible moment. There are also some
Cases in which Windows CE will take committed pages out of memory
Again, returning them to "Reserved" status:
- Since DLL and exe code can easily be re-loaded from the file system, it is often decommitted.
- Memory-mapped file pages also have well defined files to read from, so those are decommitted as well.
- Thread
Stack can shrink; if the system is very low on memory we'll scavenge
The top pages from a stack if the thread is not currently using them.
- Heaps
Can shrink; if the system is very low on memory we'll check whether
There are heap pages without data in them that can be decommitted.
However
That is where Windows CE stops. Other operating systems have a "Page
File "in which they will write other pages that don't have
Corresponding files, notably:
- Stack
- Heap
- Allocations from virtualalloc ()
- Memory-mapped files that don't actually have files underneath them (createfilemapping with invalid_handle_value)
- The writable data of executables (global variables)
Those
Operating systems have algorithms to decide that these pages have not
Been used in a while, and will write them to the page file and decommit
The ram. Windows CE does not have a page file. We'll demand-commit
Delay committing these pages as long as possible, but once they are
Committed, the operating system won't page them out again.
So,
As you see, virtual memory in its most minimal definition is just
Having a mapping between virtual addresses and physical addresses.
Lay out allocations in the address space in an efficient manner and
Avoid wasting physical memory on unallocated address space. In more
Practical terms, we also use the virtual address space to implement
Paging, avoid wasting physical memory on allocated addresses that are
Not actively being used.
People have asked, does the fact that
Windows CE 6 changes from having 32 MB of virtual memory per process
2 GB of virtual memory per process mean that Ce 6 devices now require
More Ram? And the answer is, absolutely not. Our address space just
Became sparser -- there are more free gaps between allocations.