关于mremap(2)修改内存后的释放规则及段错误问题咨询
Hey there, let's unpack your problem step by step—this is a classic case of mixing two separate memory management systems, which leads to the segfault you're seeing.
Core Release Rules for mremap()-Modified Memory
First, the key rule: malloc()/memalign() (heap allocators) and mmap()/mremap() (kernel memory mapping) are entirely separate systems—never mix their release functions!
- When
mremap()returns the same address as you passed in: This means the memory was expanded in-place, without moving. Since the memory was originally allocated viamemalign()(a heap function), it's still tracked by the heap manager's metadata. Sofree()works here because the heap can still find the info it needs to clean up the block. - When
mremap()returns a new address (triggered byMREMAP_MAYMOVE): The kernel has physically moved the memory pages to a new virtual address space. At this point, the original heap metadata is completely disconnected from the new memory block—this memory is now managed directly by the kernel, not the heap allocator. Callingfree()here causes a segfault because the heap manager can't find valid metadata for the new address, and will corrupt heap structures trying to do so.
In the second case, the only safe way to release the memory is with munmap(), since it's a kernel-managed mapping.
Why Mixing memalign() and mremap() Breaks Things
memalign() is just a specialized heap allocator—it grabs a block from the user-space heap, ensures it's aligned to your specified size, and stores metadata (like block size, pointers to adjacent blocks) near the allocated memory. When you use mremap() to move the memory, the kernel doesn't update or care about this heap metadata. The heap manager still thinks the memory is at the original address, so when you try to free() the new address, it's looking for metadata that doesn't exist there.
Switching to Anonymous mmap()
If you need to use mremap() to resize or move memory, the clean solution is to ditch memalign() entirely and use anonymous memory mappings via mmap(). This way, you're working entirely within the kernel's memory mapping system, so mremap() and munmap() will play nicely together.
Anonymous mmap() Initialization Example
Replace your memalign() call with this:
// Allocate aligned, anonymous memory directly from the kernel void *m = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (m == MAP_FAILED) { perror("mmap failed"); return EXIT_FAILURE; }
This gives you a memory block aligned to the system page size (4096 bytes, which matches your original memalign() requirement), and it's fully managed by the kernel.
Manual Reference Notes
From the Linux man pages (you can access these via man mmap, man malloc, man mremap):
malloc(3): Heap allocators may usemmap()under the hood for large blocks, but they wrap the memory with their own metadata. You must usefree()(orfreealigned()) for heap-allocated memory, nevermunmap().mmap(2): Anonymous mappings (MAP_ANONYMOUS) create private memory pages not backed by a file. These are released withmunmap().mremap(2): Explicitly designed to adjust the size or address of memory regions created bymmap(). The returned address is still a kernel-managed mapping, so usemunmap()to release it.
Fixed Example Code
Here's your original code adjusted to use anonymous mmap() instead of memalign():
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <errno.h> #include <string.h> #define ALLOC_SIZE (1024 * 1024) int main(int argc, char *argv[]) { void *m = NULL, *tmp; size_t size = 4 * ALLOC_SIZE; // Replace memalign with anonymous mmap m = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (m == MAP_FAILED) { fprintf(stderr, "mmap failed: %s\n", strerror(errno)); return EXIT_FAILURE; } tmp = mremap(m, size, size + ALLOC_SIZE, MREMAP_MAYMOVE); if (tmp == MAP_FAILED) { fprintf(stderr, "mremap(%p, %zu, %zu, MREMAP_MAYMOVE) failed: %s\n", m, size, size+ALLOC_SIZE, strerror(errno)); munmap(m, size); return EXIT_FAILURE; } else { if (tmp != m) { printf("Memory moved from %p to %p\n", m, tmp); // Kernel automatically cleans up the old mapping when MREMAP_MAYMOVE succeeds m = tmp; } size += ALLOC_SIZE; } printf("Freeing %zu bytes from %p\n", size, m); munmap(m, size); return EXIT_SUCCESS; }
内容的提问来源于stack exchange,提问作者ctuffli

