The implementation of memory management depends greatly upon operating system and architecture. Some operating systems supply an allocator for malloc, while others supply functions to control certain regions of data. The same dynamic memory allocator is often used to implement both malloc and the operator new in
C++.
Heap-based Implementation of legacy allocators was commonly done using the
heap segment. The allocator would usually expand and contract the heap to fulfill allocation requests. The heap method suffers from a few inherent flaws: • A linear allocator can only shrink if the last allocation is released. Even if largely unused, the heap can get "stuck" at a very large size because of a small but long-lived allocation at its tip which could waste any amount of address space, although some allocators on some systems may be able to release entirely empty intermediate pages to the OS. • A linear allocator is sensitive to
fragmentation. A good allocator will attempt to track and reuse free slots through the entire heap, but as allocation sizes and lifetimes get mixed it can be difficult and expensive to find or coalesce free segments large enough to hold new allocation requests. • A linear allocator has extremely poor concurrency characteristics, as the heap segment is per-process every thread has to synchronise on allocation, and concurrent allocations from threads which may have very different work loads amplifies the previous two issues.
dlmalloc and ptmalloc Doug Lea has developed the
public domain dlmalloc ("Doug Lea's Malloc") as a general-purpose allocator, starting in 1987. The
GNU C library (glibc) is derived from Wolfram Gloger's ptmalloc ("pthreads malloc"), a fork of dlmalloc with threading-related improvements. As of November 2023, the latest version of dlmalloc is version 2.8.6 from August 2012. In 2023 it was relicensed from
CC0 to
MIT-0. dlmalloc is a boundary tag allocator. Memory on the
heap is allocated as "chunks", an 8-byte
aligned data structure which contains a header, and usable memory. Allocated memory contains an 8- or 16-byte overhead for the size of the chunk and usage flags (similar to a
dope vector). Unallocated chunks also store pointers to other free chunks in the usable space area, making the minimum chunk size 16 bytes on 32-bit systems and 24/32 (depends on alignment) bytes on 64-bit systems. The mmap method averts problems with huge buffers trapping a small allocation at the end after their expiration, but always allocates an entire
page of memory, which on many architectures is 4096 bytes in size. Game developer Adrian Stone argues that , as a boundary-tag allocator, is unfriendly for console systems that have virtual memory but do not have
demand paging. This is because its pool-shrinking and growing callbacks (/) cannot be used to allocate and commit individual pages of virtual memory. In the absence of demand paging, fragmentation becomes a greater concern.
FreeBSD's and NetBSD's jemalloc Since
FreeBSD 7.0 and
NetBSD 5.0, the old malloc implementation ( by
Poul-Henning Kamp) was replaced by jemalloc, written by Jason Evans. The main reason for this was a lack of scalability of in terms of multithreading. In order to avoid lock contention, uses separate "arenas" for each
CPU. Experiments measuring number of allocations per second in multithreading application have shown that this makes it scale linearly with the number of threads, while for both phkmalloc and dlmalloc performance was inversely proportional to the number of threads.
OpenBSD's malloc OpenBSD's implementation of the malloc function makes use of
mmap. For requests greater in size than one page, the entire allocation is retrieved using mmap; smaller sizes are assigned from memory pools maintained by malloc within a number of "bucket pages", also allocated with mmap. On a call to free, memory is released and unmapped from the process
address space using munmap. This system is designed to improve security by taking advantage of the
address space layout randomization and gap page features implemented as part of OpenBSD's mmap
system call, and to detect use-after-free bugs—as a large memory allocation is completely unmapped after it is freed, further use causes a
segmentation fault and termination of the program. The GrapheneOS project initially started out by porting OpenBSD's memory allocator to Android's Bionic C Library.
Hoard malloc Hoard is an allocator whose goal is scalable memory allocation performance. Like OpenBSD's allocator, Hoard uses mmap exclusively, but manages memory in chunks of 64 kilobytes called superblocks. Hoard's heap is logically divided into a single global heap and a number of per-processor heaps. In addition, there is a thread-local cache that can hold a limited number of superblocks. By allocating only from superblocks on the local per-thread or per-processor heap, and moving mostly-empty superblocks to the global heap so they can be reused by other processors, Hoard keeps fragmentation low while achieving near linear scalability with the number of threads.
mimalloc An
open-source compact general-purpose
memory allocator from
Microsoft Research with focus on performance. The library is about 11,000
lines of code.
Thread-caching malloc (tcmalloc) Every thread has a
thread-local storage for small allocations. For large allocations mmap or
sbrk can be used. TCMalloc, a
malloc developed by Google, has garbage-collection for local storage of dead threads. The TCMalloc is considered to be more than twice as fast as glibc's ptmalloc for multithreaded programs.
In-kernel Operating system
kernels need to allocate memory just as application programs do. The implementation of malloc within a kernel often differs significantly from the implementations used by C libraries, however. For example, memory buffers might need to conform to special restrictions imposed by
DMA, or the memory allocation function might be called from interrupt context. This necessitates a malloc implementation tightly integrated with the
virtual memory subsystem of the operating system kernel. ==Overriding malloc==