分享

Linux进程间通信实现原理(2)内存映射深入分析

 汉无为 2019-06-23

还记得我之前的《Linux进程间通信实现原理(1)》这篇文章吗?,续篇来了来了,不好意思久等了大家。今天我们继续来讲Linux进程间通信实现原理系列。先简单的回顾下。

简单回顾

应用程序在运行起来之后(进程),是相互独立的,都有自己的进程地址空间。但是往往在一些业务上需要进程间的通信,来完成系统的某个完整的功能。我们来看下进程间通信能干那些事情如下:

  1. 数据传输。一个进程需要发送数据到另一个进程,这种需求肯定是存在的。

  2. 共享数据。如果有多个进程想要访问数据,一个进程修改了内容,另一个进程能够立即看到内容变化。

  3. 资源保护:上面的的操作中存在竞争情况,内核需要提供锁和同步机制。

  4. 通知:一个进程需要向另一个进程发送消息,通知发生了某个事件。

  5. 控制:有些进程需要控制另一个进程的运行。典型的例子就是gdb,可参考之前文章【gdb到底是怎么实现的?

进程间的通信方式一般可以分为八种,如下:

我们今天主题就是来深入剖析下内存映射的实现原理。

内存映射

我记得在我之前的文章中讲过一次内存映射的实现原理,不知道各位还记不记的。今天为什么还要讲呢?主要是上一次讲的还不够深入。先给个图各位回忆下:

这幅图只是讲解了大致的原理,接下来我们就仔细的研究下,到底是怎么实现的?

内存映射实现原理深入剖析

首先是创建虚拟映射区域,分为下面几个步骤

  1. 在当前的虚拟地址空间中,寻找一段满足要求大小的虚拟地址

  2. 为此虚拟地址分配一个虚拟内存区域(vm_area_struct结构,如图)

  3. 初始化该虚拟内存区域

  4. 插入该虚拟内存区域到进程的虚拟地址区域链表(也是树)中

然后是实现地址的映射关系(即:进程虚拟地址空间---->>>文件磁盘地址),分为下面几个步骤:

  1. 依次通过待映射的文件指针,文件描述符&文件结构体,最终调用内核中的mmap()

  2. 内核空间中的mmap通过虚拟文件系统inode模块 定位到文件磁盘物理地址

  3. 通过remap_pfn_range()建立页表,实现了文件地址和虚拟地址区域的映射关系。

到这里仅仅是创建了虚拟空间和映射地址,没有任何文件数据的拷贝。真正的拷贝时刻是到了进程发生了读写操作。

最后是进程访问映射空间,实现文件内容到物理内存的数据拷贝,如下步骤:

  1. 进程的读写操作,访问虚拟地址空间这一段映射地址

  2. 若进程通过写操作改变了其内容,一定时间后系统会自动回写脏页到对应的磁盘地址,即完成了写入文件的操作。(注意:修改时,脏页面不会立即更新,而是在之后的msync()来强制同步。

总结

  1. 用户空间和内核空间的高效交互;通过映射的区域直接交互的方式

  2. 数据拷贝次数减少;对文件的读取操作跨过了页缓存,减少了数据的拷贝次数

  3. 文件读取的效率高,用内存的读写方式操作IO读写方式

  4. 可实现高效的大规模数据传输,借助硬盘空间协助大数据操作时,采用mmap可提高效率

应用场景

在Linux系统中,根据内存映射的原理,它的应用场景如下:

  1. 实现内存共享:如跨进程通信

  2. 提高数据读写效率;如文件读写操作。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多