【问题标题】:How to immediately page-in newly-allocated virtual memory如何立即分页新分配的虚拟内存
【发布时间】:2015-06-02 15:19:13
【问题描述】:

我在我的 Linux 用户空间应用程序中分配了一些内存。但是,这个内存还没有物理内存支持。

为了使页面被映射,我尝试读取该区域中的每个页面,如下所示。但它并不总是对我有用。

这是我的原始代码:

void Function(void)
{
    char *memory;

    memory = malloc(4096 * 10);
}

这样分配,虚拟内存还没有映射到物理内存。

所以我修改了代码:

void Function(void)
{
    char *memory;
    volatile uint *accessMemory;

    memory = malloc(4096 * 10);
    accessMemory = (volatile uint *)memory;
    for (i = 0; i < 4096 / 10; i++) {
        printf("%X\n", *accessMemory);
        accessMemory = (volatile uint *)((uint)accessMemory + 4096);
    }
}

但我还是遇到了同样的问题。我做错了什么?

【问题讨论】:

  • 究竟是什么错误?
  • 对不起,这不是错误,但我在 arm 处理器中应用了安全扩展。有时我需要 linux 页表来映射到同一物理地址的页表。但是linux使用page-fault mechnisim所以没有将物理地址映射到页表,所以我不读取这个物理地址。在linux系统中,这不是Bug。但我的情况是这种情况造成了一个错误

标签: c linux memory memory-management


【解决方案1】:

您的代码存在明显问题,演员表是一种症状。您为 40960 个字符分配空间,但随后尝试访问无符号 409 个无符号整数,每个 4096 相隔。不仅如此,在执行算术运算之前,你还要强制指向 uint ——这很可能是一个窄化转换,而且绝对不安全。

最好将 memory 指针声明为您打算使用它的类型:

    const size_t page_size = 4096; // TODO: get actual value from system
    uint *memory;
    uint *end;
    volatile uint *p;

    memory = malloc(page_size * 10 * sizeof *memory);
    end = memory + page_size * 10;
    for (p = memory;  p < end;  p += 4096/(sizeof *p))
        printf("%X\n", *p);

说了这么多,如果你想在页面方面工作,你可能会更好地使用mmap();特别是这个选项:

MAP_POPULATE(自 Linux 2.5.46 起)
为映射填充(预设)页表。对于文件映射,这会导致文件预读。以后访问 映射不会被页面错误阻塞。 MAP_POPULATE 是 仅自 Linux 2.6.23 起支持私有映射。

【讨论】:

    【解决方案2】:

    我不太明白您在说什么“错误”,但要确保内存已预先设置错误并避免写入时复制机制(即当您尝试访问内存时不会发生页面错误)分配),您应该使用 mmap() 系统调用并将 MAP_POPULATE 标志传递给它。

    例如:

    void *addr;
    addr = mmap(NULL, 4096 * 10, PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
    

    当请求大量数据时,malloc() 无论如何都会在内部使用 mmap()(例如,对于 glibc,至少 128 kB - 这个值是可调整的)

    详见 man mmap。

    编辑:如果您想更改映射的大小,可以使用 mremap() 作为 realloc() 调用的模拟。参见 man mremap。

    但你必须小心:

    • 它是特定于 linux 的,
    • 它不允许您预先设置其他区域,
    • 不能保证在同一位置成功重新映射

    所以它可能不完全符合您的需求。在这种情况下,您应该考虑使用多个映射或以某种方式预先计算您的映射应该有多大。

    【讨论】:

    • 感谢您的评论,对不起,我正在学习英语.. 呵呵.. 但你抓住了我的问题。我会尝试你的解决方案..谢谢
    • 还有一个问题。我想用realloc怎么交换mmap?
    • @user1998727 你可以试试mremap。我已经扩展了我的答案以提供更多详细信息。
    猜你喜欢
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多