Memory Management and Virtual Memory
Virtual memory lets each process use a private logical address space while the operating system and hardware translate active pages to physical frames or backing storage.
Virtual and physical addresses
A program issues virtual addresses. The memory-management unit divides an address into a virtual page number and an offset, consults translation state, and combines the mapped physical frame with the unchanged offset.
This indirection enables isolation, relocation, shared pages, copy-on-write, and address spaces larger than physical memory. Permissions on page-table entries enforce readable, writable, and executable regions.
- Page number selects a mapping
- Offset selects a byte within the page
- Permissions are checked during translation
Page tables and the TLB
Page tables record mappings but may require multiple memory accesses. A translation lookaside buffer caches recent translations so common accesses avoid a full page-table walk.
A context switch may change the active address space. Hardware identifiers or selective invalidation can preserve safe TLB entries; otherwise stale translations must be removed.
- TLB hit: fast cached translation
- TLB miss: page-table walk
- Page-table entry may report present, dirty, accessed, and permission bits
Terms, operations, and practical uses
Address translation
- Virtual addressThe process-visible address produced by an instruction.
- Page numberSelects a translation entry.
- OffsetSelects a byte within the page and remains unchanged by translation.
- Physical frameThe block of main memory that currently stores the page.
Translation machinery
- Page tableRecords mappings, permissions, and status information for virtual pages.
- TLBCaches recent translations close to the processor.
- Page faultTransfers control to the kernel when translation cannot complete normally.
Pressure and allocation
- ReplacementSelects a resident page to evict when another frame is needed.
- ThrashingRepeated page faults caused by an active working set that does not fit in memory.
- FragmentationWasted space either between allocations or inside allocated units.
Translate a virtual address
page_size = 1024
virtual_address = 2500
page_table = {2: 7}
page = virtual_address // page_size
offset = virtual_address % page_size
physical_address = page_table[page] * page_size + offset
print('physical address', physical_address)#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
int pageSize = 1024;
int virtualAddress = 2500;
unordered_map<int, int> pageTable = {{2, 7}};
int page = virtualAddress / pageSize;
int offset = virtualAddress % pageSize;
int physicalAddress = pageTable[page] * pageSize + offset;
cout << physicalAddress << '\n';
}import java.util.Map;
class Main {
public static void main(String[] args) {
int pageSize = 1024;
int virtualAddress = 2500;
Map<Integer, Integer> pageTable = Map.of(2, 7);
int page = virtualAddress / pageSize;
int offset = virtualAddress % pageSize;
int physicalAddress = pageTable.get(page) * pageSize + offset;
System.out.println(physicalAddress);
}
}page size 1024, virtual address 2500, page 2 → frame 7physical address 7620Run the example step by step
Page faults and replacement
A page fault transfers control to the kernel because the needed mapping is absent or violates permissions. A valid but nonresident page may be loaded from storage; an invalid access terminates or signals the process.
When frames are scarce, replacement approximations such as clock use recent-access information. If a workload's active working set does not fit, repeated faults cause thrashing and useful progress collapses.
- Minor faults need no storage read
- Major faults may wait for storage
- Dirty victims must be written before reuse
Allocation and fragmentation
A language runtime or allocator manages smaller heap objects within virtual-memory regions. External fragmentation leaves separated free holes; internal fragmentation wastes space inside allocated blocks or pages.
Memory safety is a separate concern: bounds violations, use-after-free, and double-free corrupt program state. Ownership rules, garbage collection, safer languages, and runtime checks reduce different parts of that risk.
- Stack allocation follows call lifetime
- Heap allocation supports flexible lifetime
- Pooling can reduce allocation overhead
- Measure retained memory as well as allocation rate