A backend service starts and prints the address of a global variable:
Another copy of the same service may print the same address. Both processes can read and modify their own variable without affecting the other. Neither process needs to know where its bytes are actually stored in RAM, and the operating system does not need to place each process in one continuous physical-memory block.
This is possible because the address used by a program is not normally a direct physical address. It belongs to a process-specific virtual address space. The operating system and processor cooperate to connect valid virtual addresses to physical storage and to reject accesses that the process is not allowed to perform.
Virtual memory gives each process a private, controlled, and flexible view of memory that is independent of the current layout of physical RAM.
The word virtual does not mean imaginary. The program's instructions and data must ultimately come from real storage. What is virtual is the addressing view: the process sees a stable arrangement of addresses while the operating system manages the physical resources behind that arrangement.
Imagine a simple system in which every pointer used by an application is a physical RAM address. A program built to place its code at physical address 0x100000 would require that location to be available whenever it runs.
The arrangement might initially look like this:
| Physical range | Contents |
|---|---|
| 0 to 16 MiB | Operating system |
| 16 to 48 MiB | Program A |
| 48 to 96 MiB | Program B |
| 96 to 128 MiB | Free |
Several difficulties appear immediately.
If another program already occupies A's expected location, A must be relocated or cannot run. If A grows, the physical range directly after it may belong to B. If A exits, its former space may be too small or badly positioned for the next program. Every program must coordinate its physical placement with every other resident program.
Protection is also awkward. If A can construct an arbitrary physical address, it might read the operating system's memory or overwrite B's data. The system needs a reliable boundary around every program and must update those boundaries as programs start, grow, and exit.
Physical memory also becomes difficult to use efficiently. A 200 MiB process would need one continuous 200 MiB hole even if hundreds of smaller free regions existed. Its entire required image might have to occupy RAM before it could start, including code and data it never uses during that execution.
Direct physical addressing therefore couples application code to a resource that is shared, limited, fragmented, and constantly changing.
Virtual memory inserts a managed layer between the program's addresses and physical placement.
While a process runs, its instructions calculate virtual addresses. Pointers stored in variables, return addresses on a stack, and instruction addresses all belong to that process's virtual address space.
For each attempted access, the system conceptually answers three questions:
If the access is valid and its contents are ready, the hardware reaches the corresponding physical memory. If the operating system can make a valid region ready, it does so and lets the instruction continue. If the address is invalid or the operation violates the region's permissions, the operating system reports an error to the process.
This is the contract, not the detailed mechanism. The important separation is:
A virtual address is meaningful only together with a process context. The number 0x4000 can identify different bytes in two processes because each process has a different mapping.
The association can also change over time without changing the pointer stored by the program. As long as the process continues to see the same bytes with the same permitted operations, the physical location is an operating-system concern.
Virtual memory lets every process behave as though it has its own memory namespace.
Suppose Process A and Process B both use virtual address 0x6000:
The equal virtual addresses do not collide. Each is interpreted through the current process's memory context and can lead to different physical storage.
This independence simplifies both software and system management. An executable can use a consistent logical layout without first discovering where every other process resides. Starting a new process does not require rewriting pointers in existing processes. When one process exits, the operating system can reclaim its physical resources without changing the virtual addresses used by unrelated processes.
Isolation also becomes enforceable. Process A receives mappings for A's regions, not a general map of all RAM. Guessing a pointer value from Process B does not grant access to B's physical storage. The same numeric value is interpreted using A's mappings and therefore either identifies A's memory or is invalid.
This boundary contains many failures. A wild pointer in one service can corrupt that service, but it cannot normally overwrite the heap of an unrelated database process or modify kernel memory.
Threads are an intentional exception to the one-view-per-execution-stream idea. Threads in the same process share the process's virtual address space, which is why they can communicate through ordinary variables and why an invalid write from one thread can damage another thread's data.
A process often sees a virtual region as one continuous interval even when the corresponding physical storage is scattered.
Consider a 12 KiB virtual region divided conceptually into three equal pieces:
The virtual ranges are consecutive and the physical blocks behind them are not. The process cannot tell, which is the point.
From the process's perspective, the bytes are adjacent. Increasing a pointer from the end of the first piece reaches the start of the second. Physical adjacency is unnecessary because the memory system translates each covered portion independently.
This changes the allocation problem. The operating system can use available physical pieces wherever they exist instead of finding one hole large enough for the entire process. A process can also grow a virtual region when suitable physical memory is available elsewhere; it does not require the physical address immediately following its current allocation.
Virtual contiguity is therefore an abstraction provided to software. It should not be confused with physical contiguity, which some devices and low-level operations may still require.
This flexibility greatly reduces the external-fragmentation problem that would arise if every whole process needed one variable-sized physical interval. It does not eliminate all forms of memory waste: the system still allocates and tracks memory in finite units, and allocators inside a process can still fragment their own regions.
A process's virtual address space is usually much larger than the amount of physical memory it is actively using.
That is useful because programs commonly create address ranges whose contents are used only partially or intermittently. Examples include:
The operating system can arrange for physical memory to be committed to useful portions as they are needed. Inactive contents may come from an executable or another backing store, and clean contents that can be recreated do not always need to remain in RAM.
Suppose a service has a 2 GiB virtual heap range but has written to only 120 MiB of it. The 2 GiB range describes available addresses in the service's view. It does not by itself prove that 2 GiB of RAM is occupied.
The virtual heap range visible to the process is 2 GiB, but it is used in scattered pieces: roughly 64 MiB in one region and 56 MiB in another, with untouched space in between and after. Only about 120 MiB is actively used.
The exact physical usage depends on which parts have been accessed, which contents are shared, and what the operating system currently keeps resident. The essential lesson is that address-space capacity and current RAM residency are different quantities.
This separation lets programs start without loading every instruction and byte of data into RAM first. It also lets the system devote scarce physical memory to the portions of active processes that are doing useful work now.
Virtual memory does not make physical capacity irrelevant. If active workloads collectively require more physical memory than the system can support efficiently, performance can fall sharply or an allocation can fail. Storage is much slower than RAM, and continuously moving contents between them can overwhelm useful execution.
Without virtual memory, leaving a large unused gap between two program regions would appear wasteful because the gap might reserve real physical addresses or RAM.
With virtual memory, an unmapped gap is mainly a range of numbers for which no valid mapping exists. It need not consume matching physical memory.
A 64-bit process can therefore have a layout like:
The numeric distance between regions does not measure the amount of RAM between them. There may be no physical storage behind the gaps at all.
Sparse layouts have practical benefits. Stacks can be given room to grow without immediately occupying that amount of RAM. Guard regions can remain inaccessible so an overflowing stack is more likely to fail at a boundary. Major regions can be placed far apart, making accidental cross-region accesses less likely to land in valid memory.
A large virtual address space is therefore a namespace in which the operating system can arrange mappings. It is not one giant allocation of physical memory.
Virtual memory does more than relocate addresses. Each mapped region can carry access permissions.
Program instructions are commonly readable and executable but not writable. Ordinary data is commonly readable and writable but not executable. Constants can be readable but not writable. Unmapped ranges permit no access.
When an instruction requests a write, the memory system checks write permission for that virtual region. It does not merely ask whether some physical bytes exist. The same underlying storage can be exposed with different permissions in different contexts.
This gives the operating system a precise way to enforce process boundaries and region roles. A process cannot make a read-only region writable merely by casting away a language qualifier. Nor can it access an unmapped address by constructing a pointer with the desired number.
Virtual-memory protection works at the granularity of mapped regions, not individual language objects. If two C objects occupy the same writable region, writing beyond one object may corrupt the other without crossing a protected boundary. Virtual memory is therefore a foundation for isolation, but it is not a replacement for memory-safe code.
Private address spaces do not require every byte to have a separate physical copy.
The operating system can connect virtual regions in multiple processes to common physical storage. For example, two processes can execute the same read-only library instructions while each sees those instructions within its own address space.
Sharing is selective. The library region can refer to common storage while heaps, stacks, and writable globals remain private. The shared region can even appear at different virtual addresses in the two processes because virtual address equality is not required for physical sharing.
This creates a useful combination:
Virtual memory provides private namespaces by default and controlled sharing where the operating system deliberately creates it.
Sharing read-only content avoids redundant physical copies. Sharing writable memory can support communication between cooperating processes, but it must be requested and synchronized because changes become visible across the shared mapping.
Consider a newly started web service. Its virtual address space contains regions for executable instructions, constants, writable globals, dynamic allocation, shared libraries, and thread stacks.
The service does not need all of these contents in RAM at startup.
The request parser and startup code may become active immediately. A rarely used administrative endpoint may remain untouched. Each worker thread may receive a virtual stack range with space to grow while initially using only a small part. The memory allocator may manage a large virtual arena even though the service has created few objects.
At the same time, other instances of the same service can use the same virtual layout. Each instance has private request state and heap objects. Read-only executable and library contents can be backed by common physical storage.
The resulting view is:
This division of responsibility is the reason application code can allocate memory and follow pointers without coordinating RAM positions with every other process on the server.
It also explains an important operational observation: a process can have a very large virtual address-space size while using far less physical memory. The large number may represent reserved ranges, sparse mappings, and shared content rather than an equally large private RAM footprint.
A common simplified definition says that virtual memory lets a computer use disk when RAM runs out. That describes one possible behavior, but it misses the main abstraction.
A system benefits from virtual memory even if it has no swap space and never moves anonymous process data to disk. It still gains:
Executable instructions and file-derived data may already have durable copies outside RAM, but backing storage is not what makes an address virtual. Translation and process-specific mappings do.
A better definition is:
Virtual memory is a system for presenting process-specific address spaces and mapping their valid regions to physical resources under operating-system control.
Using storage to extend the set of contents that can exist outside RAM is one capability built on that system, not its complete purpose.
Virtual memory solves difficult placement and protection problems, but it is not free.
The operating system must maintain mapping information for processes. The processor must translate virtual addresses during execution. Changes to mappings require coordination with cached translation state. Accessing a valid region whose contents are not currently ready can pause the process while the operating system supplies them.
Memory access patterns also matter. A program that repeatedly touches a compact active set is usually easier to support efficiently than one that jumps unpredictably across a very large region. If too many actively used contents compete for too little physical memory, the system can spend more time managing memory than running application code.
These costs explain why virtual memory is carefully supported by both hardware and operating-system policy. The abstraction is valuable enough to justify substantial machinery, but application behavior still determines how efficiently that machinery can serve the workload.
Virtual memory provides isolation and flexible addressing, but several conclusions do not follow from it.
It does not provide infinite memory. A process can possess unused virtual addresses and still fail to obtain usable memory because of physical capacity, system policy, or resource limits.
It does not guarantee that every allocated byte is currently in RAM. A virtual range and its current physical residency describe different things.
It does not guarantee physical contiguity. A contiguous virtual buffer can be assembled from separate physical locations.
It does not make all memory private. Regions can be deliberately shared, and threads in one process use the same address space.
It does not detect every invalid program operation. An out-of-bounds access can remain inside a writable mapped region and silently corrupt another object.
It does not make memory access uniform in cost. Translation is normally fast, but access locality, missing contents, and memory pressure can cause large performance differences.
The abstraction is powerful precisely because it separates concerns. It gives programs a controlled view while leaving physical placement and residency to the operating system. It does not erase the limits of the resources underneath.
Loading simulation...
Virtual memory exists to separate the memory view used by a process from the changing layout and limited capacity of physical memory. Each process receives a private virtual address space whose mappings define which addresses are valid, what operations they permit, and which physical resources supply their contents.
This separation provides isolation, relocation, sparse layouts, controlled sharing, and contiguous virtual regions backed by noncontiguous physical memory. It also allows physical memory to be devoted to actively needed contents instead of requiring an entire process image to remain in RAM.
Virtual memory is not simply disk used as extra RAM, nor does it provide infinite capacity or complete protection from programming errors. It is a managed addressing abstraction that makes safe and efficient multiprogramming practical.
5 quizzes