【问题标题】:What happens if computer hangs while persisting a memory-mapped file?如果计算机在持久化内存映射文件时挂起会怎样?
【发布时间】:2015-09-09 18:50:34
【问题描述】:

我对使用托管内存映射文件available since .NET 4.0 非常感兴趣。

检查从 MSDN 中提取的以下语句:

持久化文件是与 磁盘上的源文件。当最后一个进程完成工作时 文件,数据保存到磁盘上的源文件中。这些 内存映射文件适用于处理非常大的文件 源文件。

我的问题是:如果计算机在保存内存映射文件时挂起会怎样?

我的意思是,由于内存映射文件存储在虚拟内存中(我理解这是在页面文件中),也许可以从虚拟内存中恢复一个文件,并在重新启动Windows后尝试将其再次存储到源文件中.

【问题讨论】:

    标签: c# .net .net-4.0 crash memory-mapped-files


    【解决方案1】:

    作为内存映射文件基础的数据页驻留在操作系统缓存(文件缓存)中。每当您关闭 Windows 时,它都会将所有修改过的缓存页面写入文件系统。

    缓存中的页面要么是普通文件数据(来自对文件进行读/写的进程),要么是由分页系统读/写的内存映射页面。

    如果 Windows 无法(例如崩溃或死机)将缓存内容刷新到磁盘,则该数据将丢失。

    【讨论】:

      【解决方案2】:

      如果启用持久化,内存映射文件在重启后不会删除。

      您可以使用带有显示数据有效或无效的标志的原子操作过程,如果有效,您可以恢复其他数据丢失

      如果您的操作系统支持(内核或文件系统生命周期),如 unix,您可以使用共享内存,其同步速度比映射文件更快

      Modern Operating Systems 3e (2007) 书籍内存映射文件: 共享库实际上是一种称为内存映射文件的更通用工具的特例。这里的想法是,进程可以发出系统调用来将文件映射到其虚拟地址空间的一部分。在大多数实现中,在映射时没有引入任何页面,但是当页面被触及时,它们被要求一次一个地分页,使用磁盘文件作为后备存储。当进程退出或显式取消映射文件时,所有修改的页面都会写回文件。映射文件为 I/O 提供了另一种模型。可以将文件作为内存中的大字符数组访问,而不是进行读取和写入。在某些情况下,程序员发现这种模型更方便。如果两个或多个进程同时映射到同一个文件,它们可以通过共享内存进行通信。当另一个进程从其虚拟地址空间映射到文件的部分读取时,一个进程对共享内存所做的写入立即可见。因此,这种机制在进程之间提供了一个高带宽通道,并且经常被这样使用(甚至在映射临时文件的范围内)。现在应该清楚了,如果内存映射文件可用,共享库可以使用这种机制

      http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2044.html

      共享内存

      POSIX 将共享内存对象定义为“表示可以同时映射到多个进程的地址空间的内存的对象”。 共享内存类似于文件映射,用户可以映射共享内存对象的多个区域,就像内存映射文件一样。在某些操作系统(如 Windows)中,共享内存是文件映射的一种特殊情况,其中文件映射对象访问由系统分页文件支持的内存。但是,在 Windows 中,这块内存的生命周期在最后一个连接到共享内存对象的进程关闭连接或应用程序退出时结束,因此没有数据持久性。如果应用程序创建共享内存,用数据填充它并退出,则数据将丢失。此生命周期称为进程生命周期 在 POSIX 操作系统中,共享内存的生命周期是不同的,因为对于信号量、共享内存和消息队列,在对象不再被任何进程引用后,必须保留对象及其状态(包括数据,如果有的话)。对象的持久性并不意味着对象的状态在系统崩溃或重新启动后被保留,但这可以实现,因为共享内存对象实际上可以实现为永久文件系统的映射文件。共享内存销毁发生在显式调用 unlink() 时,类似于文件销毁机制。 POSIX 共享内存需要具有内核生命周期(对象被显式销毁或在操作系统重新启动时被销毁)或文件系统持久性(共享内存对象与文件具有相同的生命周期)。 这种寿命差异对于实现可移植性很重要。许多可移植的运行时都试图在 Windows 和 POSIX 共享内存之间实现完美的可移植性,但本文的作者还没有看到任何令人满意的努力。向 POSIX 共享内存添加引用计数仅在进程不崩溃时才有效,这是非常常见的。使用本机共享内存在 Windows 中模拟 POSIX 行为是不可能的,因为我们可以尝试将共享内存转储到文件以获得持久性,但进程崩溃会避免持久性。唯一可行的替代方法是在 Windows 中使用内存映射文件来模拟共享内存,但尽可能避免文件内存同步。 许多其他命名的同步原语(如命名的互斥锁或信号量)也面临同样的生命周期可移植性问题。自动共享内存清理在许多情况下都很有用,例如共享库或 DLL-s 与其他 DLL-s 或进程通信。即使发生崩溃,操作系统也会自动清理资源。当启动程序可以创建和填充另一个进程可以读取或修改的共享内存时,POSIX 持久性也很有用。如果服务器进程崩溃,持久性还允许数据恢复。所有数据仍在共享内存中,服务器可以恢复其状态。 本文提出 POSIX 生命周期(内核或文件系统生命周期)作为一种更便携的解决方案,但对此没有强烈的看法。 C++ 委员会应考虑这两种方法的用例,以决定哪种行为更好,或者两种选择是否都可用,从而强制修改 POSIX 和 Windows 系统。

      【讨论】:

      • 顺便说一句,这适用于 Windows 吗? :(
      • @MatíasFidemraizer 我没有在窗口上测试它,但我看到数据库使用内存映射文件来稳定数据库,如 MongoDB
      • 是的,我知道 Mongo 使用 MMP,顺便说一句,谁知道它在 Windows 中的行为:\
      • 关于持久性,持久性 MMP 会在最后一个打开它的进程结束时刷新到它们的源文件。我的意思是,如果进程因为计算机崩溃而结束,那么我怀疑源文件不会被写入......
      • 崩溃不是正常退出和文件不删除,如果服务器进程崩溃,持久性也允许数据恢复。所有数据仍在共享内存中,服务器可以恢复其状态,但您必须检查数据是否有效
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-09
      • 1970-01-01
      • 2018-07-27
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多