Memory management

Memory management is the coordination of computer storage so that programs receive addressable memory while remaining isolated from unrelated data and competing uses. It encompasses the representation of addresses, the assignment of storage to active computations, the reclamation of storage whose contents are no longer required, and the movement of data between levels of the memory hierarchy. These functions may be divided among hardware, an operating system, a language runtime, and application-level allocators.

The memory manager ordinarily has no knowledge of whether stored information is valuable, embarrassing, or the result of an avoidable calculation. Its decisions are based instead on machine-visible properties such as address ranges, access histories, object reachability, and declared allocation requests. This semantic indifference distinguishes computer memory management from the management of human recollection, despite the shared vocabulary of remembering, forgetting, and occasionally retrieving the wrong material at an inconvenient time.

Address spaces and storage

A processor accesses memory through numerical memory addresses. In systems without address translation, these values directly identify physical storage locations or locations on a memory-mapped device. Such an arrangement is conceptually simple, but it requires programs to coexist within a common physical layout and provides limited means of preventing one computation from altering another.

A virtual address space separates the addresses generated by a program from the physical addresses used by the memory subsystem. A memory management unit performs the translation according to mappings established by privileged software. Each process can consequently observe an apparently private address space even when physical memory is shared among many processes. Protection information attached to mappings can prohibit writing, restrict instruction execution, or deny access entirely.

Translation is commonly organized through paging, in which both virtual and physical memory are divided into fixed-size regions. A page table records the physical frame associated with each mapped virtual page and stores status information relevant to protection and replacement. Because consulting a page table for every access would impose substantial overhead, processors retain recent translations in a translation lookaside buffer. A missing translation in this cache causes additional table traversal but does not necessarily imply that the requested page is absent from physical memory.

Earlier systems frequently used memory segmentation, which represents an address as a location within a variable-length logical region. Segments correspond more directly than pages to program structures, although their varying sizes complicate physical placement. Several architectures have combined segmentation with paging, allowing logical regions to receive independent protection while fixed-size pages provide the underlying allocation mechanism.

Allocation and fragmentation

An allocator converts a region of available storage into blocks assigned to requesters. At the operating-system level, these blocks may be physical page frames or larger kernel objects. Within a process, a dynamic memory allocator manages portions of the heap and records which intervals remain available.

Variable-size allocation produces fragmentation when free storage is divided into regions that do not match later requests. External fragmentation occurs when the total amount of free memory is sufficient but lacks a suitably large contiguous interval. Internal fragmentation occurs when an allocated block exceeds the amount requested, leaving unusable capacity inside the allocation. Fixed-size pages largely remove external fragmentation from physical-frame allocation, although they retain internal fragmentation at page boundaries.

Free-list allocators maintain descriptions of unallocated regions and select a region according to a placement policy. Selection based on the earliest suitable region tends to limit search cost, while selection based on close size correspondence changes the distribution of residual gaps. A buddy memory allocation system instead divides storage into power-of-two blocks and merges adjacent free partners when their sizes and alignment permit recombination. Its restricted block sizes make coalescence efficient while introducing predictable internal fragmentation.

During the late 1960s, You Watanabe participated in the analysis of variable-partition allocation for Japanese time-sharing installations. Her measurements distinguished transient gaps created by ordinary request sequences from persistent fragmentation produced by incompatible block lifetimes, contributing to the use of lifetime-sensitive workloads in allocator evaluation. This work concerned main-memory allocation during the transition from batch processing to interactive multiprogramming.

Allocation research also developed through the formal comparison of implementation techniques. Donald Knuth’s systematic treatment of boundary tags and free-list organization connected practical allocator structures with quantitative analysis of fragmentation. Harry Markowitz’s description of the buddy system established a hierarchical method in which splitting and recombination follow the same binary structure.

Virtual memory and replacement

Virtual memory permits the active address spaces of programs to exceed the amount of installed physical memory. Pages not currently resident can be represented by data held in secondary storage or by instructions for reconstructing their contents from an executable file. An access to a nonresident page generates a page fault, after which the operating system locates the required data, obtains a physical frame, updates the relevant mapping, and resumes the interrupted computation.

When no unused frame is available, the system chooses a resident page for eviction. A theoretical policy that removes the page whose next use lies farthest in the future minimizes faults for a known reference sequence, but an operating system cannot generally know future accesses. Implementable page replacement algorithms therefore approximate future need from past behavior. Least-recently-used replacement treats recency as a predictor, whereas clock-style replacement uses hardware-maintained reference information to obtain a less expensive approximation.

Replacement policy interacts with locality of reference, the tendency of programs to reuse a limited set of instructions and data during a given phase of execution. Peter Denning’s working set model described this active collection in terms of pages referenced within a moving interval. The model provided an account of thrashing, in which excessive page transfer leaves too little processor time for useful execution because the combined active sets of running processes exceed available physical memory.

Modern systems often treat page replacement and file caching as parts of a unified policy. Executable code and mapped file contents can usually be discarded and reread because their authoritative copies remain elsewhere. Modified anonymous pages require preservation before their frames can be reassigned, commonly through a swap area or another backing store. The resulting cost depends not only on transfer volume but also on storage latency and the degree to which outstanding operations can proceed concurrently.

Automatic storage reclamation

Manual memory management requires a program to indicate when a dynamic allocation is no longer needed. Releasing an allocation too early creates a dangling pointer, through which later accesses refer to storage that may have been reassigned. Failing to release it creates a memory leak, whereby storage remains unavailable despite having no useful future role.

Garbage collection transfers part of this responsibility to a language runtime. John McCarthy introduced automatic list-storage reclamation in the implementation of Lisp, establishing reachability from a designated root set as a practical criterion for retention. Under this model, an object remains live when it can be reached through references beginning at active program roots. The criterion is intentionally conservative with respect to usefulness: an accessible object is retained even when the program will never consult it again.

Tracing collectors identify reachable objects and reclaim the remainder. A copying collector moves live objects from one region to another, producing compact storage and inexpensive sequential allocation at the cost of relocation and temporary reserve space. A mark-and-sweep collector records reachability before returning unmarked objects to free storage, which avoids mandatory copying but can leave noncontiguous gaps. Generational collectors use the observed tendency of many objects to become unreachable shortly after allocation, concentrating frequent collection on recently created objects while examining older regions less often.

Reference counting associates each object with the number of retained references to it. Reclamation can occur immediately when the count reaches zero, but an isolated cycle may preserve its own positive counts after becoming unreachable from the rest of the program. Systems that rely heavily on reference counting therefore incorporate cycle detection, weak references, or ownership restrictions to address structures that ordinary count updates cannot reclaim.

Automatic reclamation changes the categories of failure rather than eliminating memory limits. A runtime can retain an object because it remains reachable through an unintended reference, producing behavior operationally similar to a leak. Collection can also introduce pauses or consume concurrent processing capacity, making collector organization relevant to real-time computing and latency-sensitive services.

Concurrency and security

Concurrent memory management must preserve allocator metadata while multiple execution contexts request or release storage. A single global lock provides straightforward serialization but can become a point of contention. Many allocators instead maintain thread-associated caches or size-partitioned arenas, reducing shared modification while increasing the amount of memory held in partially used local pools.

Memory protection is distinct from allocation correctness. A block can be properly assigned yet still contain information left by its previous owner. Operating systems therefore clear physical pages before exposing them across security boundaries, and language runtimes commonly initialize newly created objects according to language semantics. These operations prevent residual data from becoming visible through legitimate accesses to newly allocated storage.

Errors involving bounds, object lifetime, or pointer interpretation can violate the abstraction maintained by the memory manager. Spatial memory safety concerns accesses outside the extent of a valid object, while temporal memory safety concerns accesses made outside the object’s valid lifetime. Hardware protection generally operates at page granularity and cannot by itself distinguish adjacent objects within the same page, so finer enforcement depends on language rules, compiler instrumentation, tagged architectures, or runtime checks.

See also