You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于mremap(2)修改内存后的释放规则及段错误问题咨询

mremap() Memory Release Rules & Why memalign() + mremap() Causes Segfaults

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 via memalign() (a heap function), it's still tracked by the heap manager's metadata. So free() works here because the heap can still find the info it needs to clean up the block.
  • When mremap() returns a new address (triggered by MREMAP_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. Calling free() 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 use mmap() under the hood for large blocks, but they wrap the memory with their own metadata. You must use free() (or freealigned()) for heap-allocated memory, never munmap().
  • mmap(2): Anonymous mappings (MAP_ANONYMOUS) create private memory pages not backed by a file. These are released with munmap().
  • mremap(2): Explicitly designed to adjust the size or address of memory regions created by mmap(). The returned address is still a kernel-managed mapping, so use munmap() 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:43:52