操作系统知识强化内存映射文件(25王道)

内存映射文件

本文根据25王道操作系统内存映射文件这一章所作跟课笔记

什么是内存映射文件

首先来看看什么是内存映射文件。简单来说,这是操作系统向上层的程序员提供的一个系统调用功能。通过这个功能,程序员可以很方便的去访问文件数据,另外这个功能也可以很方便的让多个进程共享同一个文件的数据。


先来解释第一点,为什么说内存映射文件可以让程序员更方便的去使用文件数据呢?那作为对比,我们先来看一下传统的文件访问方式。
来看一个例子,这是一个文件,名字叫葵花宝典.txt,这个文件要存放到磁盘里边。那磁盘的存储空间是以块为单位的,这样的一块大小是1 KB,那相应的这个文件就会被拆分成几个大小相等的块。每个块刚好是1 KB,刚好可以放到这个磁盘里边,那这些块有可能被离散的存放到磁盘的各个角落。


就像这个样子。那如果一个进程想要访问这个文件的数据,应该怎么做呢?
传统的做法是这样的,首先我们知道每个进程,它拥有自己的虚拟地址空间。那如果这个进程想要访问这个文件的数据,首先它需要使用open系统调用来指明,打开这个文件。接下来需要使用seek系统调用来指明它想要读取这个文件的哪部分数据。那操作系统会用一个读写指针来记录这个位置。


接下来进程可以使用read系统调用来指明从这个位置往后,它想要读入多少的数据?比如读入十个字节,或者读入20个字节等等。


那如果这一次进程要读入的这部分数据,刚好是存放在文件的第二个块这儿。那么,接下来操作系统就会把这一块的数据给读入内存。

image.png


现在这部分的数据被读入内存了,那进程就可以去访问内存里的这部分数据了。当然,进程也可以修改这一块的数据。最后如果想让刚才的修改被保存,那么这个进程它还需要使用write系统调用,把内存里的这一块数据写回磁盘。
所以这种传统的文件访问方式看起来很麻烦,那能不能让读写文件数据的这些操作变得更简单呢?

这就是内存映射文件要解决的问题。
来看一下,如果一个操作系统,它支持内存映射文件的功能,那么一个程序员或者说一个进程,它访问文件的方式就会变得更简单。
首先需要先使用open系统调用指明打开一个文件。接下来使用mmap这个系统调用,让操作系统把文件映射到进程的虚拟地址空间当中。

image.png


也就是这个样子。

image.png


那这个系统调用会给程序员返回一个指针。指向刚才映射的这片区域的起始地址。那接下来你就可以用访问内存的方式去访问这些文件数据了。什么意思呢?在c语言程序。,如果给你一个起始地址,某一个指针,那么你是不是可以用这个指针,再加上某一个地址的偏移量,去访问这个指针后面的某些区域对吧?
所以只要mmap这个系统调用给程序员返回了这片区域的起始地址。那接下来用这个指针就可以访问到这个文件的任何一个数据。
那你会发现在这个图里边,我们把文件的三个块涂成了灰色,原因是在使用mmap系统调用之后。操作系统只是建立了文件数据和内存之间的一个映射关系,但并没有把文件数据直接给读入内存。这就相当于一个缺页的状态。

假定,此时你要访问的数据刚好是在文件的第二块,在这个部分,

image.png


那此时操作系统发现这一块的数据还没有调入主存,也就是出现了一个缺页异常。此时操作系统会自动的把这一块的数据给读入主存。那同样的道理,如果你此时想要访问第三块数据,而第三块数据此时还处于缺页状态的话,那操作系统会自动的帮你把第三块数据读到内存里。

image.png


也就是说,我们作为程序员,我们不需要再自己去调用read函数,读入数据的过程是由操作系统自动的帮我们完成的。那这些数据被读入内存之后,那么进程就可以对它们为所欲为。比如说我可以修改第二块的数据。最后如果说这个进程它不再需要使用这个文件,那么进程可以使用close系统调用来关闭文件。
当它关闭文件之后,操作系统会自动的把文件当中被修改的数据给写回磁盘。那第二块数据是被修改过的,而第三块数据是没有被修改过的,所以操作系统会把第二块数据写回磁盘。


因此可以看到采用内存映射文件之后,程序员对文件数据的访问就方便多了。它只需要知道这个文件在内存当中的起始地址,接下来按照访问内存的方式去访问这个文件当中的数据就可以。那文件数据的读入或者写出都是由操作系统自动来完成的,相比之下,传统的文件访问方式需要程序员自己去调用read和write系统调用才可以读入文件的数据或者写出文件的数据。


实现文件的共享


那接下来我们再来解释内存映射文件的第二个作用,可以实现文件数据的共享。葵花宝典.txt这个文件,它可以被进程一用系统调用的方式映射到自己的虚拟地址空间里。


那同样的道理,另一个进程进程二也可以把这个文件映射到自己的虚拟地址空间里边,那此时两个进程的虚拟地址空间是相互独立的。但是操作系统会把这两块虚拟地址空间映射到相同的物理内存上。


操作系统只需要修改这两个进程的页表,让对应的页面映射到相同的一个物理页框上。那这么做,就可以让两个进程实际上是在共享同一份文件的数据。在这种情况下,当一个进程修改了文件的数据之后,另一个进程立马也可以看到这一块文件数据的改变。所以通过内存映射文件的方式多个进程,它们可以共享同一个文件的数据。
最后补充一点文件数据的读入和写出完全是由操作系统来负责的,就是什么时候要读入一个文件的数据块,什么时候要写出一个文件的数据块,这都是由操作系统来控制的。这么做的好处在于操作系统,它可以通过某些策略去优化磁盘IO的效率。比如说用预读入或者缓写出这样的策略,可以优化IO的效率。

若有收获,就点个赞吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值