Linux mmap() 的非持久性后备存储

Linux non-persistent backing store for mmap()

首先,提供一点激励人心的背景信息:我有一个基于 C++ 的服务器进程,它 运行 在嵌入式 ARM/Linux-based 计算机上运行。它工作得很好,但作为其操作的一部分,它创建了一个相当大的固定大小数组(例如几十到几百兆字节)的 temporary/non-persistent 状态信息,它目前保存在堆上,并且它访问 and/or 不时更新该数据。

我正在调查我可以将事情扩展到什么程度,我 运行 遇到的一个问题是最终(当我通过使服务器的配置越来越大来对服务器进行压力测试时),这个数据结构变得大到足以导致内存不足的问题,然后 OOM 杀手出现,随之而来的是普遍的不满。请注意,Linux 的嵌入式配置没有启用交换,我不能(轻松地)启用交换分区。

我有一个关于如何改善这个问题的想法是在计算机的本地闪存分区上分配这个大数组,而不是直接在 RAM 中,然后使用 mmap() 使它在服务器进程中看起来像它一样仍在内存中。这将大大减少 RAM 的使用,我希望 Linux 的文件系统缓存能够掩盖大部分由此产生的性能成本。

我唯一真正关心的是文件管理——特别是,我想避免任何用 "orphan" 后备存储文件(即进程不支持的旧文件)填满闪存驱动器的机会不再存在,但该文件仍然存在,因为它的创建过程崩溃或由于其他错误忘记在退出时删除它)。我还希望能够 运行 在同一台计算机上同时运行多个服务器实例,而不会相互干扰。

我的问题是,Linux 是否有任何内置工具来处理此类用例?我特别想用某种方法来标记文件(或 mmap() 句柄或类似文件),以便在创建进程的文件退出或崩溃时,OS 自动删除文件(类似于当进程退出或崩溃时,Linux 已经自动恢复了进程分配的所有 RAM。

或者,如果 Linux 没有任何内置的自动临时文件清理功能,人们是否可以使用 "best practice" 来确保大型临时文件不会被删除?由于无意中变得持久而最终填满了一个驱动器?

请注意,AFAICT 只是将文件放在 /tmp 中对我没有帮助,因为 /tmp 使用的是 RAM 磁盘,因此与简单地分配进程内堆存储相比,它不会给我任何 RAM 使用优势.

我相信这是特定于文件系统的,但大多数 Linux 文件系统都允许删除打开的文件。该文件将仍然存在,直到关闭它的最后一个句柄。我建议您打开该文件,然后立即将其删除,当您的进程因任何原因退出时,它会自动清理。

有关详细信息,请参阅此 post:What happens to an open file handle on Linux if the pointed file gets moved, delete

是的,您 create/open 文件。然后你remove()文件的文件名。

该文件仍将由您的进程打开,您可以 read/write 它就像任何打开的文件一样,并且当打开该文件的进程退出时它会消失。

我相信此行为是由 posix 强制执行的,因此它可以在任何类似 unix 的系统上运行。即使在硬重启时,space 也会被回收。

是的,我一直这样做...

open 文件,unlink 它,使用 ftruncate 或(更好)posix_fallocate 使其大小合适,然后使用 mmap MAP_SHARED 将其映射到您的地址 space。如果需要,您可以立即 close 描述符;内存映射本身将保留文件。

为了提高速度,您可能会想帮助 Linux 管理其页面缓存。您可以使用 posix_madvisePOSIX_MADV_WILLNEED 来建议内核将数据分页,并使用 POSIX_MADV_DONTNEED 来建议内核释放页面。

您可能会发现 last 无法按您希望的方式工作,尤其是对于脏页。您可以使用 sync_file_range 明确控制刷新到磁盘。 (尽管在那种情况下你会希望保持文件描述符打开。)

除了 Linux-特定的 sync_file_range.

之外,所有这些都是完全标准的 POSIX