【问题标题】:is it safe to ftruncate a shared memory object after it has ben mmap'ed?在映射后对共享内存对象进行截断是否安全?
【发布时间】:2012-10-19 00:51:00
【问题描述】:
  • shm_open()
  • mmap() 带有预定义的大 length
  • fork()(多次)
  • ftruncate()随意

这样做的目的是确保fork() 产生的每个进程在同一地址上都有一个共享段。然而,我不想让 RAM 一直忙,而是动态调整它的大小(大小跨越 0 - 大 length)。

这行得通吗?有UB吗?

【问题讨论】:

    标签: linux memory-management posix shared-memory


    【解决方案1】:

    不,没关系。您可以随时截断基础文件,但如果您访问超出文件边界的内存,您可能会收到SIGBUS。因此,您需要非常小心,不要触及超出文件当前长度的内存(或捕​​获 SIGBUS 并处理它)。

    来自man 2 mmap:

    使用映射区域可能会产生以下信号:

    SIGBUS 试图访问不对应的缓冲区的一部分 文件(例如,超出文件末尾,包括大小写 另一个进程截断了文件)。

    【讨论】:

    • 这就是我的假设,但munmap 触发器是否会写入可能触发SIGBUS 的脏页?
    • 将此标记为已接受,因为它回答了我的问题。但是 Damon 的方法更易于管理(我可以在 mmaped 范围的中间卸载页面)。
    • @nneonneo 我认为这不太对。我相信您需要在ftruncate 之后执行mremap 来更新映射。尽管如此,您仍然应该最初分配一个较大的大小,以防止 mremap 因 ENOMEM 而失败。
    • @jleahy:实际上,我的意思是你不需要mremap,但是访问文件末尾之后的内存可能会导致崩溃。在实践中,mremap 更安全。
    • @nneonneo 如果另一个进程共享文件的映射怎么办?然后一个进程可以通过将文件缩小并在无辜进程中触发 SIGBUS 来对另一个进程发起拒绝服务攻击(Linux 肯定不允许这样做吗?)
    【解决方案2】:

    不要调整它的大小。

    我不想让 RAM 一直忙

    这就是内核将使用虚拟内存为您做的事情。只要您不使用mlock() 或MAP_LOCKED,它将在必要/适当时分页。

    【讨论】:

    • 好吧,内存和交换。我可能会在某个时候在映射区域的中间使用一些东西(强制内核提交它),但是在运行时的其余部分我可能会忘记它。所以我认为我需要一种方法来明确告诉我不再使用地址空间的那部分。
    • 您可以使用madvise(),但请注意,不能保证行为。
    • 我想我会使用MADV_REMOVE。但是,如果我需要收回那个空间,我该怎么办?
    • 如果不知道更多细节,我想你会更喜欢MADV_DONTNEED。
    【解决方案3】:

    创建任意大小的映射,除非您实际使用它,否则它不会“让 RAM 保持忙碌”。

    如果您担心在使用完 RAM 后 保持忙碌,请致电 madvise(MADV_DONTNEED) - 如果您访问它们,这将清除页面并从零池中返回新页面再次。

    【讨论】:

    • 在写入标记为MADV_DONTNEED的范围之前,我不需要执行任何操作,对吧?
    • 请注意,零填充行为仅在后备存储不再具有这些页面的情况下(因为它可能是在某些数据可能已被ftruncate 丢弃的问题中)。
    • @LorenzoPistone:您无需做任何事情,不。 MADV_DONTNEED 将丢弃页面并(如果由文件支持)根据需要透明地从磁盘重新加载页面,或者(匿名映射)只是向您抛出一个零页面。请注意,后者 - 至少在我看来 - 实际上是“不正确的”行为,因为 POSIX 声明语义没有改变(情况确实如此!)。不过,这正是您想要的。
    猜你喜欢
    • 2021-04-12
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 2011-12-05
    • 2015-11-01
    相关资源
    最近更新 更多