我有一个场景,我需要在一个进程空间中线性地映射文件的非线性部分。
例如, 如果文件是10页,我可能需要先映射3,跳过4和最后3。 映射应该是线性的,s.t。进程空间中的增量访问允许转到第3页之后的文件的第8页,如第4,5,6页和第4页所示。 7没有映射。
我想知道这是否可以在Linux中使用。
感谢。
答案 0 :(得分:4)
使用mmap()
多次调用MAP_FIXED
为第二次和后续映射指定固定地址的策略应该有效,但问题是如果有任何事情已经映射到内存中第一个映射,它将被破坏,因为MAP_FIXED
会自动取消映射在制作新映射之前的任何内容。
我在这里看了一下Linux系统地址空间中某些映射的布局,我观察到,至少在某些时候,内核为内存映射选择的地址从高地址向下增长到一个低地址。也就是说,新映射被赋予紧邻最近现有映射所使用的地址空间下方的地址空间。根据该策略,当您进行第一次映射时,几乎可以保证紧跟在该映射之后的地址空间已被其他东西占用(并且它可能也很重要,就像系统库一样)。其他系统(不同的内核版本,不同的体系结构,或非Linux等等)可能会使用不同的地址空间分配策略,这些策略不会使这个问题变得不可能,但您应该假设它可以发生并通过使用来防范它以下技术。
首先制作一个虚拟映射,它是要构造的所有映射的大小的总和。因此,如果你想映射文件的前3页,然后跳过4,然后再映射三个,做一个6页的虚拟映射。
对于这种虚拟映射,您只需映射匿名内存(MAP_ANONYMOUS
)。感谢Basile Starynkevitch建议也使用MAP_NORESERVE
进行此映射。
使用MAP_FIXED
指定您希望每个映射显示的精确地址,将此虚拟映射逐条替换为您实际需要的文件的映射。
编辑:我最初建议在重新使用地址空间进行新映射之前使用munmap()
销毁虚拟映射,但感谢jstine指出这是不必要的(如果您的程序是多线程的,它会引入竞争条件。
对于第一个映射,请使用虚拟映射的起始地址。计算第二个映射的地址,作为虚拟映射的起始地址加上第一个映射的大小。这应该在第一个映射结束后立即放置第二个映射。等等第三和第四个映射。在您的方案中,所有内容都是页面大小和页面对齐的,因此不会因对齐而产生间隙。
在完成第2步中的所有映射之后,原始虚拟映射应该没有任何内容。
答案 1 :(得分:4)
除了Celada的previous answer之外,您可能还会对remap_file_pages(2)之后的Linux特定mmap(2)系统调用感兴趣。
第一个mmap
可能会使用MAP_NORESERVE
来避免花费交换空间(只保留地址空间,而不是数据)。