dan*_*368 6 java linux ipc memory-mapped-files mappedbytebuffer
在我的应用程序中,有一个进程将数据写入文件,然后响应接收到的请求,将通过网络向请求进程发送(一些)该数据。这个问题的基础是看当两个进程碰巧在同一台主机上时,我们是否可以加快通信速度。(就我而言,进程是 Java,但我认为这个讨论可以更广泛地适用。)
有一些项目使用 Java 的 FileChannel.map() 返回的 MappedByteBuffers 作为在同一主机上的 JVM 之间共享内存 IPC 的一种方式(参见 Chronicle Queue、Aeron IPC 等)。
加速同主机通信的一种方法是让我的应用程序使用其中一种技术为同主机通信提供请求-响应路径,结合现有的写入数据文件的机制,或者通过提供一种统一的通信和写入文件的方式。
另一种方法是允许请求进程直接访问数据文件。
我倾向于支持第二种方法 - 假设它是正确的 - 因为它更容易实现,并且似乎比为每个请求复制/传输数据副本更有效(假设我们没有替换现有的写入机制到文件)。
本质上,我想了解当两个进程访问同一个文件并使用它进行通信时究竟发生了什么,特别是 Java (1.8) 和 Linux (3.10)。
根据我的理解,如果两个进程同时打开同一个文件,它们之间的“通信”本质上将通过“共享内存”进行。
请注意,此问题与是否使用 MappedByteBuffer 对性能的影响无关 - 与读取和写入文件相比,使用映射缓冲区以及减少复制和系统调用似乎很可能会减少开销,但是可能需要对应用程序进行重大更改。
以下是我的理解:
所以总而言之,如果我理解正确的话——虽然映射提供了性能优势,但它似乎并没有提供任何我们尚未从 Linux 和页面缓存的性质中获得的“共享内存”功能。
所以,请让我知道我的理解在哪里。
谢谢。
本质上,我试图了解当两个进程同时打开同一个文件时会发生什么,以及是否可以使用它来安全、高效地提供进程之间的通信。
如果您使用常规文件使用read和write操作(即不进行内存映射),那么这两个进程不会共享任何内存。
Buffer与文件关联的 Java 对象中的用户空间内存不在地址空间之间共享。write进行系统调用时,数据将从一个进程地址空间中的页面复制到内核空间中的页面。(这些可能是页面缓存中的页面。这是特定于操作系统的。)read进行系统调用时,数据从内核空间中的页面复制到读取进程地址空间中的页面。必须这样做。如果与读取器和写入器关联的操作系统共享页面在其背后处理缓冲区,那么这将是一个安全/信息泄漏漏洞:
write(...),也许永远不会。read(...)只有write(...)单个字节。当然:您可以安全地使用读写文件在两个进程之间传输数据。但是您需要定义一个协议,使读者能够知道作者写入了多少数据。读者知道作者何时写了一些东西可能需要进行投票;例如查看文件是否已被修改。
如果您仅从通信“通道”中的数据复制角度来看待这一点
使用内存映射文件,您可以将数据从应用程序堆对象复制(序列化)到映射缓冲区,然后再次从映射缓冲区复制(反序列化)到应用程序堆对象。
对于普通文件,有两个额外的副本:1)从写入进程(非映射)缓冲区到内核空间页面(例如在页面缓存中),2)从内核空间页面到读取进程(非映射)缓冲区。
下面的文章解释了传统读/写和内存映射的情况。(这是在复制文件和“零复制”的上下文中,但您可以忽略它。)
参考: