Linux中多个进程使用文件指针读取文件时是不是使用共享虚拟内存?
Posted
技术标签:
【中文标题】Linux中多个进程使用文件指针读取文件时是不是使用共享虚拟内存?【英文标题】:Is shared virtual memory used when multiple processes read a file using file pointer in Linux?Linux中多个进程使用文件指针读取文件时是否使用共享虚拟内存? 【发布时间】:2015-04-29 02:01:38 【问题描述】:我编写了一个使用文件指针读取文件的 C++ 程序。而且我需要同时运行多个进程。由于文件的大小可能很大(100MB~),为了减少多个进程的内存使用,我认为我需要使用共享内存。 (例如像boost::interprocess::shared_memory_object
这样的IPC库)
但它真的需要吗?因为我认为如果多个进程读取同一个文件,那么每个进程的虚拟内存通过页表映射到文件的相同物理内存。
我读了一个 Linux 文档,他们说,
共享虚拟内存
虽然虚拟内存允许进程有独立的(虚拟的) 地址空间,有时您需要共享进程 记忆。例如,系统中可能有多个进程 运行 bash 命令外壳。而不是拥有几份 bash,每个进程一个虚拟地址空间,最好是 在物理内存中只有一个副本并且所有进程都在运行 bash 分享它。动态库是另一个常见的例子 执行多个进程之间共享的代码。共享内存可以 也可用作进程间通信 (IPC) 机制,具有 两个或多个进程通过共同的内存交换信息 其中。 Linux 支持 Unix TM System V 共享内存 IPC。
另外,维基说,
在计算机软件中,共享内存要么是
一种进程间通信 (IPC) 方法,即在同时运行的程序之间交换数据的一种方法。一个过程 将在 RAM 中创建一个其他进程可以访问的区域,或者 一种节省内存空间的方法,方法是将访问通常是数据片段的副本指向单个实例 相反,通过使用虚拟内存映射或明确支持 有问题的程序。这最常用于共享库 和 XIP。
因此,我真正好奇的是操作系统级别是否支持共享虚拟内存?
提前致谢。
【问题讨论】:
这可能是题外话,但答案是肯定的。 “一个进程将在 RAM 中创建一个其他进程可以访问的区域”——例如,操作系统和它提供的“System V 共享内存”的各种低级机制促进了这一点。 “虚拟内存映射”同样如此。 “共享库”的加载、链接和分页也是如此(尽管后者发生在用户空间中) 我不确定你在问什么,但看起来 mmap (linux.die.net/man/2/mmap) 就是你要找的。现在 100MB 并不是那么大,至少与现代 RAM 大小相比;如果你有空闲的 RAM 并且需要提高性能,我会说去内存映射。 @sabreitweiser 100MB 不是很大的内存使用量,但是如果运行多个多个进程并且它们都将文件加载到内存上,那么它可能会占用非常大的内存。我已经考虑过 mmap 和 boost 内存映射库,但想知道这项工作是否需要。 @SeongeunSo 如果我的理解是正确的, mmap 会创建一个副本,然后在各个进程之间共享该副本。这比访问同一文件的许多进程好还是坏,您可能需要通过分析来找到,或者至少告诉我们更多关于用例的信息。除了各个级别的透明缓存之外,我不确定与普通 File 对象相关的开销有多大,但我认为您需要大量进程来克服映射整个文件所需的内存。 我不确定,如果我理解正确的话。你认为这会自动发生吗?一个进程打开一个文件,该文件被映射到内存中,而另一个进程打开同一个文件时,使用的是同一个内存映射? 【参考方案1】:关于您的第一个问题 - 如果您希望您的数据可以被多个进程访问而不会重复,那么您肯定需要某种共享存储。
在 C++ 中,我肯定会使用 boost 的 shared_memory_object
。这是在进程之间共享(大)数据的有效选项,并且它有很好的示例文档 (http://www.boost.org/doc/libs/1_55_0/doc/html/interprocess/sharedmemorybetweenprocesses.html)。
使用mmap()
是一种更底层的方法,通常在C 中使用。要将其用作IPC,您必须使映射区域共享。来自http://man7.org/linux/man-pages/man2/mmap.2.html:
MAP_SHARED
分享此映射。对映射的更新可见 映射此文件的其他进程,并被携带 通过底层文件。该文件实际上可能不是 在调用 msync(2) 或 munmap() 之前进行更新。
在该页面上还有一个将文件映射到共享内存的示例。
在任何一种情况下,至少要记住两件事:
如果有多个进程修改共享数据,则需要同步。
您不能使用指针,只能使用映射区域开头的偏移量。 这是来自 boost 文档的解释:
如果多个进程映射同一个文件/共享内存,那么每个进程的映射地址肯定是不同的。由于每个进程可能以不同的方式使用其地址空间(例如分配或多或少的动态内存),因此无法保证文件/共享内存将映射到同一地址。
如果两个进程将同一个对象映射到不同的地址,这会使该内存中指针的使用无效,因为指针(这是一个绝对地址)只对写入它的进程有意义。解决这个问题的方法是使用对象之间的偏移量(距离)而不是指针:如果两个对象被一个进程放置在同一个共享内存段中,每个对象的地址在另一个进程中会不同,但它们之间的距离它们(以字节为单位)将是相同的。
关于操作系统支持 - 是的,粉碎内存是操作系统特定的功能。
在Linux中mmap()
实际上是在内核和模块中实现的,可以用来在用户和内核空间之间传输数据。
Windows 也有它的特点:
Windows 共享内存创建与可移植共享内存创建有点不同:段的大小必须在创建对象时指定,不能像共享内存对象那样通过截断来指定。请注意,当附加到共享内存的最后一个进程被销毁时,共享内存也被销毁,因此本机 Windows 共享内存没有持久性。
【讨论】:
【参考方案2】:你的问题没有意义。
我想我需要使用共享内存。 (例如像
boost::interprocess::shared_memory_object).
这样的IPC库
如果你使用共享内存,内存是共享的。
我认为如果多个进程读取同一个文件,那么每个进程的虚拟内存通过页表映射到文件的相同物理内存。
现在您要讨论的是内存映射 I/O。这不是一回事。然而,在这种情况下,它更有可能是您所需要的。
【讨论】:
以上是关于Linux中多个进程使用文件指针读取文件时是不是使用共享虚拟内存?的主要内容,如果未能解决你的问题,请参考以下文章