我在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);
}
}
但我仍然遇到同样的问题。我做错了什么?
答案 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。
但你必须小心:
所以它可能不完全符合您的需求。在这种情况下,您应该考虑使用多个映射或以某种方式预先计算映射的大小。
答案 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以来仅支持私有映射。