linux - 映射文件的非线性部分
Posted
技术标签:
【中文标题】linux - 映射文件的非线性部分【英文标题】:linux - map nonlinear parts of file 【发布时间】:2012-12-30 02:20:01 【问题描述】:我有一个场景,我需要在进程空间中线性映射文件的非线性部分。
例如, 如果文件是 10 页,我可能需要映射前 3 页、跳过 4 页和最后 3 页。 映射应该是线性的,s.t.进程空间中的增量访问允许在第 3 页之后转到文件的第 8 页,因为未映射第 4、5、6 和 7 页。
我想知道这在 Linux 中是否可行。
谢谢。
【问题讨论】:
这不只是多次调用mmap
的情况吗?
多次调用 mmap 不会为每个 mmap 调用提供一个指针结果吗?我有这样的场景,整个映射只需要一个指针结果。不可行吗?
我已经有一段时间没有对mmap
做任何事情了,但是其中一个参数不是可选地址吗?
是的,第一个参数。因此,您建议多次调用 mmap,但是从第二次调用病房开始,使用上一次调用的结果作为第一个参数?
@OliCharlesworth 是否存在进程空间中的线性访问问题..来自linux.die.net/man/2/mmap ...内核将第一个参数作为有关放置映射位置的提示;在 Linux 上,映射将在附近的页面边界处创建。
【参考方案1】:
使用MAP_FIXED
多次调用mmap()
为第二次和后续映射指定固定地址的策略应该可以工作,但问题是如果在第一次映射后立即映射到内存中,它将被破坏,因为MAP_FIXED
在进行新映射之前会自动取消映射曾经存在的任何内容。
我在这里查看了 Linux 系统地址空间中一些映射的布局,我观察到,至少在某些时候,内核为内存映射选择的地址从高地址向下增长到一个低地址。即,在最近的现有映射所使用的地址空间之下的地址空间被赋予一个新的映射。在该策略下,当您进行第一次映射时,几乎可以保证紧随该映射的地址空间已经被其他东西占用(并且它可能也很重要,例如系统库)。其他系统(不同的内核版本、不同的体系结构或非 Linux 等)可能使用不同的地址空间分配策略,这不会使这个问题不太可能发生,但您应该假设它可能发生并通过使用来防止它发生以下技术。
首先创建一个虚拟映射,它是您要构建的所有映射大小的总和。所以如果你想映射文件的前 3 页,然后跳过 4 页,然后再映射 3 页,做一个 6 页的虚拟映射。
对于这个虚拟映射,您可以只映射匿名内存 (MAP_ANONYMOUS
)。感谢Basile Starynkevitch 建议也使用MAP_NORESERVE
进行此映射。
将此虚拟映射逐个替换为您实际需要的文件的映射,使用MAP_FIXED
指定您希望每个映射出现的精确地址。
编辑:我最初建议在将地址空间重新用于新映射之前使用munmap()
破坏虚拟映射,但感谢jstine 指出这是不必要的(并且它引入了如果您的程序是多线程的,则会出现竞争条件)。
对于第一个映射,使用虚拟映射的起始地址。计算第二个映射的地址为虚拟映射的起始地址加上第一个映射的大小。这应该将第二个映射放在第一个映射结束之后。第三个和第四个映射依此类推。在您的场景中,所有内容都是页面大小和页面对齐的,因此不会因对齐而出现间隙。
在步骤 2 中完成所有映射后,原始虚拟映射应该没有任何剩余。
【讨论】:
如果你控制之外的另一个程序在你破坏虚拟映射后立即使用 mmap 并意外选择了这个漂亮的免费“洞”,会发生什么?我不相信这可以可靠地工作 @sl0815:您正在映射到虚拟内存,不是吗?所以其他程序不会影响你。 (但是,我不评论这种策略是否可靠......) 我应该更仔细地阅读那些手册页。 @everyone:忽略我上面的愚蠢评论。 实用提示:MAP_FIXED
无需调用munmap()
。 MAP_FIXED
标志忽略了通常的内核预留检查,因此您可以使用已经预留的地址指定它,它只会隐式破坏之前映射到那里的任何内存。这是 MAP_FIXED posix 标准的一部分。
@jstine 事实证明这很重要,所以我将使用该信息编辑答案。【参考方案2】:
除了 Celada 的 previous answer 之外,您可能还会对 mmap(2) 之后的 Linux 特定的 remap_file_pages(2) 系统调用感兴趣。
第一个mmap
可能会使用MAP_NORESERVE
来避免消耗交换空间(并且只保留地址空间,而不是数据)。
【讨论】:
感谢您提供的其他想法。我不知道remap_file_pages()
和MAP_NORESERVE
。我希望是非常特定于 Linux 且不可移植的 :-)
AFAIR,MAP_NORESERVE
在其他一些系统(也许是 Solaris)上可用。但是remap_file_pages
确实是非常特定于 Linux 的。以上是关于linux - 映射文件的非线性部分的主要内容,如果未能解决你的问题,请参考以下文章