如何立即页面调入新分配的虚拟内存

时间:2015-06-02 15:19:13

标签: c linux memory memory-management

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

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

这是我的原始代码:

void Function(void)
{
    char *memory;

    memory = malloc(4096 * 10);
}

像这样分配,虚拟内存尚未映射到物理RAM。

所以我修改了代码:

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);
    }
}

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

2 个答案:

答案 0 :(得分:1)

我不太明白你在谈论什么是“Bug”,但要确保内存是预先设定的,并且避免了写时复制机制(即当你试图访问内存时不会发生页面错误你应该使用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的,
  • 它不允许您预先删除其他区域,
  • 无法保证在同一位置成功重新映射

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

答案 1 :(得分: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起)
  填充(prefault)页表以进行映射。对于文件映射,这会导致对文件进行预读。以后访问   页面错误不会阻止映射。 MAP_POPULATE是   自Linux 2.6.23以来仅支持私有映射。