【问题标题】:Memory reallocation using mremap使用 mremap 重新分配内存
【发布时间】:2014-07-03 07:13:36
【问题描述】:

我正在尝试使用 malloc 分配两个不同的 4096 字节,并使用不同的值初始化这些分配。之后,我希望其中一个指针指向另一个分配“不”改变 p1 的值和“不”复制数据。我想将第二个分配“重新映射”到第一个分配,这基本上应该改变进程页表中的虚拟地址,即不涉及复制。当我运行此代码时,我得到 mremap 失败。知道如何做到这一点吗?

int main(){
    char *p1 = (char *)malloc(4096);
    memset(p1, 'a', 4096);
    char *p2 = (char *)malloc(4096);
    memset(p2, 'b', 4096);
    printf("p1 is %c at address %p\n", p1[0], p1);
    printf("p2 is %c at address &p\n", p2[0], p2);
    free(p1);
    /* remapping virtual addresses */
    void *p0 = mremap(p2, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, p1);
    /* checking */
    printf("p0 is %c at address %p\n", p0[c], p0);
    return 0;
}

预期输出: p1 是地址 xxx p2 是 b 在地址 yyy p0 是地址 xxx 处的 b

【问题讨论】:

  • 来自手册页:“如果指定了 MREMAP_FIXED,则还必须指定 MREMAP_MAYMOVE。”您是否可能需要按位 & 而不是 |?
  • @cecilg23:它们都是指定的。按位 | 对组合位标志是正确的 - 按位 & 通常总是给你零。

标签: c linux memory-management


【解决方案1】:

malloc() 返回的地址可能不是页面对齐的,所以mremap()errno 设置为EINVAL。如果我使用mmap() 而不是malloc(),并修复代码中的语法错误:

#define _GNU_SOURCE 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

int main(void) {
    char *p1 = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    memset(p1, 'a', 4096);

    char *p2 = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    memset(p2, 'b', 4096);

    printf("p1 is %c at address %p\n", p1[0], (void *)p1);
    printf("p2 is %c at address %p\n", p2[0], (void *)p2);

    void *p0 = mremap(p2, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, p1);
    if ( p0 == MAP_FAILED ) {
        perror("mremap: mremap failed");
        return EXIT_FAILURE;
    }

    printf("p0 is %c at address %p\n", ((char *)p0)[0], p0);
    return EXIT_SUCCESS;
}

然后我得到:

paul@local:~/src/c/scratch$ ./mremap
p1 is a at address 0x7f5addb71000
p2 is b at address 0x7f5addb70000
p0 is b at address 0x7f5addb71000
paul@local:~/src/c/scratch$ 

【讨论】:

  • 谢谢。不过,快速的问题是,如何在首先释放(取消映射)p1 之前重新映射到 p1?
  • 因为C让你做各种事情。我不一定推荐这是一个好主意,只是使用mmap() 作为获取页面对齐地址的便捷方式。
  • hmmm 所以这基本上将 p1 指向的虚拟页面的页表条目覆盖到 p2 指向的物理页面。我知道了。多谢。这真的很有帮助。
  • 必须重新映射而不先取消映射其中的内容,除非您对程序中运行的每一段代码都有极高的控制水平。如果您先取消映射,则地址范围不再属于您,并且您最终可能会在执行重新映射时破坏稍后分配的其他内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 2019-11-11
  • 2013-02-24
  • 2021-12-30
  • 1970-01-01
相关资源
最近更新 更多