我有几个关于Linux系统中 mmap
实现的问题,这些问题似乎没有太多的文档:
使用 mmap
将文件映射到内存时,如何处理预取文件中的数据?
即,当您从映射的区域读取数据时会发生什么?该数据是否移动到 L1/L2 缓存中?是否直接从磁盘缓存中读取?prefetchnta
和类似的 ASM 指令是否可用于 mmap
区域?
mmap
实际调用的开销是多少?它相对于映射数据量而言是恒定的还是与之成比例的?
希望有人对此有深入了解。先谢谢了。
mmap基本上是对虚拟内存子系统的程序化访问。
当你有一个1G的文件,并且将其mmap,你会得到一个指向整个文件的指针,就好像它在内存中一样。
然而,在此阶段除了实际映射操作为文件在VM中保留页面外,什么也没有发生。(当然,文件越大,映射操作时间越长。)
为了从文件开始读取数据,只需通过mmap调用返回的指针进行访问。
如果希望"预加载"文件的某些部分,只需访问想要预加载的区域。确保访问想要加载的所有页面,因为VM只会加载您访问的页面。例如,假设在您的1G文件中,您有一个10MB的"索引"区域需要映射。最简单的方法是只需"遍历您的索引"或任何数据结构,让VM根据需要分页数据。或者,如果您"知道"它是文件的"前10MB",并且您的VM的页面大小为4K,则只需将mmap指针转换为char指针,然后遍历页面。
void load_mmap(char *mmapPtr) {
// We'll load 10MB of data from mmap
int offset = 0;
for(int offset = 0; offset < 10 * 1024 * 1024; offset += 4 * 1024) {
char *p = mmapPtr + offset;
// deref pointer to force mmap load
char c = *p;
}
}
关于L1和L2缓存,mmap与此无关,这完全取决于您如何访问数据。
由于您正在使用底层VM系统,因此任何在mmap块内寻址数据的内容都可以工作(甚至是从汇编语言)。
如果您不更改任何mmap的数据,则VM将随着需要新页面而自动清除旧页面。如果您实际上更改了它们,那么VM将为您写回这些页面。
回答Ravi Phulsundar先生的问题:
只要权限设置正确,多个进程可以将同一文件映射为长期使用。查看mmap手册页,只需传递MAP_SHARED
标志(如果需要映射一个非常大的文件,请改用mmap2):
MAP_SHARED
与所有映射此对象的其他进程共享此映射。 将区域存储相当于写入文件。 直到调用msync(2)或munmap(2),文件可能实际上并未更新。
你使用MAP_SHARED
mlock
不是预加载页面吗? - Giovanni Funchalreadahead
的手册,但它接受一个文件描述符,不清楚我是否可以使用我用于mmap文件的那个描述符。 - cYrus