mremap(2)
๐ mremap(2) โ remap a virtual memory address ๐
okay bestie, settle in, because this is the System Calls Manual entry for mremap(2) and she is lowkey a whole icon. it's a standard C library thing (libc, -lc), she lives in Linux, and she is about to let you resize a chunk of memory without copying a single byte. no cap. ๐
โจ NAME โจ
mremap โ remap a virtual memory address
๐ LIBRARY ๐
Standard C library (libc, -lc)
๐ซถ SYNOPSIS ๐ซถ
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/mman.h>
void *mremap(size_t old_size;
void old_address[old_size], size_t old_size,
size_t new_size, int flags, ... /* void *new_address */);
(yeah that prototype is a little cursed, she's built different, we love her anyway ๐ )
๐ธ DESCRIPTION ๐ธ
mremap() expands (or shrinks) a memory mapping you already have, and โ plot twist โ she might move it somewhere else at the same time. that whole relocation situation is controlled by the flags argument and by how much virtual address space is actually free. ๐ฆ
Mappings can also just be moved with no resizing at all: you pass equal old_size and new_size and throw in the MREMAP_FIXED flag (details below, keep reading bestie). Since Linux 6.17, when you're doing a simple move, old_address has to be mapped, but old_size is allowed to span multiple mappings โ including unmapped gaps sitting between them. you can also drop MREMAP_DONTUNMAP in there.
Similarly, if the operation is a shrink โ meaning old_size is bigger than new_size โ then old_size is also allowed to span multiple mappings, and those mappings don't even have to be next to each other, no adjacency required. if that shrink happens in-place, meaning neither MREMAP_FIXED nor MREMAP_DONTUNMAP is specified, then new_size may span multiple VMAs too. however ๐ฅ if the range is moved, then new_size has to span only a single mapping. rules are rules.
If the operation is neither a MREMAP_FIXED move nor a shrink, then old_size must span only a single mapping. periodt.
old_addressโ the old address of the first virtual memory block you wanna expand, shrink, and/or move. โ ๏ธ note:old_addresshas to be page aligned.old_sizeโ the size of the range containing the virtual memory blocks being manipulated.new_sizeโ the requested size of the virtual memory blocks after the resize.new_addressโ an optional fifth argument, may be provided; see theMREMAP_FIXEDdescription below.
If the value of old_size is zero, and old_address refers to a shareable mapping (see the description of MAP_SHARED in mmap(2)), then mremap() will create a new mapping of the same pages. new_size becomes the size of that new mapping, and you can specify where it goes with new_address (see MREMAP_FIXED below). ๐ if you request a new mapping this way, the MREMAP_MAYMOVE flag must also be specified.
The flags bit-mask argument may be 0, or it may include the following flags:
MREMAP_MAYMOVEโ by default, if there isn't enough space to expand a mapping right where it currently sits,mremap()just fails, sad. if this flag is specified, the kernel is permitted to relocate the mapping to a new virtual address if that's what it takes. โ ๏ธ if the mapping gets relocated, then absolute pointers into the old mapping location become invalid โ use offsets relative to the starting address of the mapping instead, bestie, i'm begging you.MREMAP_FIXED(since Linux 2.3.31) โ this flag does a similar job to theMAP_FIXEDflag ofmmap(2). specify it andmremap()accepts a fifth argument,void *new_address, which specifies a page-aligned address the mapping must be moved to. any previous mapping in the address range specified bynew_addressandnew_sizegets unmapped. ๐- If
MREMAP_FIXEDis specified, thenMREMAP_MAYMOVEmust also be specified. - Since Linux 6.17, if
old_sizeequalsnew_sizeandMREMAP_FIXEDis specified, thenold_sizemay span beyond the mapping in whichold_addressresides. in that case, gaps between mappings in the original range are maintained in the new range. the whole operation is performed atomically unless an error arises โ and if an error does arise, the operation may be partially completed, i.e. some mappings moved and others not. ๐ - Moving multiple mappings is not permitted if any of those mappings have either been registered with
userfaultfd(2), or map drivers that specify their own custom address mapping logic.
- If
MREMAP_DONTUNMAP(since Linux 5.7) โ this flag, which must be used together withMREMAP_MAYMOVE, remaps mappings to a new address but does not unmap them from their original address. she duplicates and dips. โจ- the
MREMAP_DONTUNMAPflag can only be used with mappings that are notVM_DONTEXPANDorVM_PFNMAP. before Linux 5.13, it could only be used with private anonymous mappings (see the description ofMAP_PRIVATEandMAP_ANONYMOUSinmmap(2)). - after completion, any access to the range specified by
old_addressandold_sizewill result in a page fault. that page fault gets handled by auserfaultfd(2)handler if the address sits in a range previously registered withuserfaultfd(2). otherwise, the kernel just allocates a zero-filled page to handle the fault. - the
MREMAP_DONTUNMAPflag may be used to atomically move a mapping while leaving the source mapped. see NOTES for some possible applications. ๐
- the
If the memory segments specified by old_address and old_size are locked (using mlock(2) or similar), then that lock is maintained when the segments get resized and/or relocated. as a consequence, the amount of memory locked by the process may change. ๐ซถ
โญ RETURN VALUE โญ
On success, mremap() returns a pointer to the new virtual memory area. ๐
On error, the value MAP_FAILED is returned โ that's (void *) -1 โ and errno is set to indicate the error.
๐ ERRORS ๐
EAGAINโ the caller tried to expand a memory segment that is locked, but that wasn't possible without blowing past theRLIMIT_MEMLOCKresource limit.EFAULTโ some address in the rangeold_addresstoold_address+old_sizeis an invalid virtual memory address for this process. you can also getEFAULTeven if there exist mappings covering the whole address space you asked for, but those mappings are of different types, and themremap()operation being performed doesn't support that. ๐ญEINVALโ an invalid argument was given. possible causes are:old_addresswas not page aligned;- a value other than
MREMAP_MAYMOVEorMREMAP_FIXEDorMREMAP_DONTUNMAPwas specified inflags; new_sizewas zero;new_sizeornew_addresswas invalid;- the new address range specified by
new_addressandnew_sizeoverlapped the old address range specified byold_addressandold_size; MREMAP_FIXEDorMREMAP_DONTUNMAPwas specified without also specifyingMREMAP_MAYMOVE;MREMAP_DONTUNMAPwas specified, but one or more pages in the range specified byold_addressandold_sizewere not private anonymous;MREMAP_DONTUNMAPwas specified andold_sizewas not equal tonew_size;old_sizewas zero andold_addressdoes not refer to a shareable mapping (but see BUGS);old_sizewas zero and theMREMAP_MAYMOVEflag was not specified.
ENOMEMโ not enough memory was available to complete the operation. possible causes are:- the memory area cannot be expanded at the current virtual address, and the
MREMAP_MAYMOVEflag is not set inflags. or, there is not enough (virtual) memory available. MREMAP_DONTUNMAPwas used, causing a new mapping to be created that would exceed the (virtual) memory available. or, it would exceed the maximum number of allowed mappings.
- the memory area cannot be expanded at the current virtual address, and the
๐ STANDARDS ๐
Linux. ๐ง (she's exclusive like that)
๐ HISTORY ๐
Before glibc 2.4, glibc did not expose the definition of MREMAP_FIXED, and the prototype for mremap() did not allow for the new_address argument. throwback era, we don't miss it. ๐
๐ NOTES ๐
mremap() changes the mapping between virtual addresses and memory pages. this can be used to implement a very efficient realloc(3). slay. ๐
In Linux, memory is divided into pages. a process has (one or) several linear virtual memory segments. each virtual memory segment has one or more mappings to real memory pages (in the page table). each virtual memory segment has its own protection (access rights), which may cause a segmentation violation (SIGSEGV) if the memory is accessed incorrectly โ for example, writing to a read-only segment. accessing virtual memory outside of the segments will also cause a segmentation violation. ๐ญ
If mremap() is used to move or expand an area locked with mlock(2) or equivalent, the mremap() call will make a best effort to populate the new area, but will not fail with ENOMEM if the area cannot be populated.
๐ฆ MREMAP_DONTUNMAP use cases ๐ฆ
Possible applications for MREMAP_DONTUNMAP include:
- Non-cooperative
userfaultfd(2): an application can yank out a virtual address range usingMREMAP_DONTUNMAPand then employ auserfaultfd(2)handler to handle the page faults that subsequently occur as other threads in the process touch pages in the yanked range. iconic behaviour, honestly. - Garbage collection:
MREMAP_DONTUNMAPcan be used together withuserfaultfd(2)to implement garbage collection algorithms (e.g., in a Java virtual machine). such an implementation can be cheaper (and simpler) than conventional garbage collection techniques that involve marking pages with protectionPROT_NONEin conjunction with the use of aSIGSEGVhandler to catch accesses to those pages. ate. ๐ฅ
๐ BUGS ๐
Before Linux 4.14, if old_size was zero and the mapping referred to by old_address was a private mapping (see the description of MAP_PRIVATE in mmap(2)), mremap() created a new private mapping unrelated to the original mapping.
this behavior was unintended and probably unexpected in user-space applications (since the whole intention of mremap() is to create a new mapping based on the original mapping). since Linux 4.14, mremap() fails with the error EINVAL in this scenario. glow-up complete. โจ
๐ SEE ALSO ๐
brk(2), getpagesize(2), getrlimit(2), mlock(2), mmap(2), sbrk(2), malloc(3), realloc(3)
your favorite text book on operating systems for more information on paged memory (e.g., Modern Operating Systems by Andrew S. Tanenbaum, Inside Linux by Randolph Bentson, The Design of the UNIX Operating System by Maurice J. Bach) ๐
and that's the whole page bestie!! ๐ฅณ this one came straight out of Linux man-pages 6.20, dated 2026-02-08 โ so if you're reading this, shoutout to the man-pages girlies keeping mremap(2) immaculate for us. now go forth and remap responsibly, mwah ๐๐๐ซถ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: GPL-2.0-or-later
- Copyright 1996, Tom Bjorkholm <tomb@mydata.se>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms