# 【NO.557】Linux内存管理-详解mmap原理

## **1. 一句话概括mmap**

mmap的作用，在应用这一层，是让你把文件的某一段，当作内存一样来访问。将文件映射到物理内存，将进程虚拟空间映射到那块内存。

这样，进程不仅能像访问内存一样读写文件，多个进程映射同一文件，还能保证虚拟空间映射到同一块物理内存，达到内存共享的作用。

## **2.** 虚拟内存**？虚拟空间？**

其实是一个概念，前一篇对于这个词没有确切的定义，现在定义一下：

虚拟空间就是进程看到的所有地址组成的空间，虚拟空间是某个进程对分配给它的所有物理地址（已经分配的和将会分配的）的重新映射。

而虚拟内存，为啥叫虚拟内存，是因为它就不是真正的内存，是假的，因为它是由地址组成的空间，所以在这里，使用虚拟空间这个词更加确切和易懂。（不过虚拟内存这个词也不算错）

### **2.1 虚拟空间原理**

#### **2.1.1物理内存**

首先，物理地址实际上也不是连续的，通常是包含作为主存的DRAM和IO寄存器

![img](https://pic4.zhimg.com/80/v2-acf9edf723cc9fec950f48a4bf72158f_720w.webp)

以前的CPU（如X86）是为IO划分单独的地址空间，所以不能用直接访问内存的方式（如指针）IO，只能用专门的方法（in/read/out/write）诸如此类。

现在的CPU利用PCI总线将IO寄存器映射到物理内存，所以出现了基于内存访问的IO。

还有一点补充的，就如同进程空间有一块内核空间一样，物理内存也会有极小一部分是不能访问的，为内核所用。

#### **2.1.2三个总线**

这里再补充下三个总线的知识，即：地址总线、数据总线、控制总线

- 地址总线，用来传输地址
- 数据总线，用来传输数据
- 控制总线，用来传输命令

比如CPU通过控制总线发送读取命令，同时用地址总线发送要读取的数据虚地址，经过MMU后到内存

内存通过数据总线将数据传输给CPU。

虚拟地址的空间和指令集的地址长度有关，不一定和物理地址长度一致，比如现在的64位处理器，从VA角度看来，可以访问64位的地址，但地址总线长度只有48位，所以你可以访问一个位于2^52这个位置的地址。

#### **2.1.3虚拟内存地址转换（虚地址转实地址）**

上面已经明确了虚拟内存是虚拟空间，即地址的集合这一概念。基于此，来说说原理。

如果还记得操作系统课程里面提到的虚地址，那么这个虚地址就是虚拟空间的地址了，虚地址通过转换得到实地址，转换方式课程内也讲得很清楚，虚地址头部包含了页号（段地址和段大小，看存储模式： 页存储、段存储，段页式），剩下部分是偏移量，经过MMU转换成实地址。

![img](https://pic3.zhimg.com/80/v2-77aad2f066c524ae9e3e12123f54ea42_720w.webp)

存储方式

![img](https://pic3.zhimg.com/80/v2-210e67b7c2b59e0c583e3c9f0c3221de_720w.webp)

如图则是页式存储动态地址变换的方式

虚拟地址头部为页号通过查询页表得到物理页号，假设一页时1K，那么页号*偏移量就得到物理地址

![img](https://pic4.zhimg.com/80/v2-135c6be0231c3323b0a3aa5a315d4447_720w.webp)

如图所示，段式存储

虚拟地址头部为段号，段表中找到段基地址加上偏移量得到实地址

![img](https://pic2.zhimg.com/80/v2-940e5377430e3cb2d64f3afea2a20489_720w.webp)

段页式结合两者，如图所示。

## **3. mmap映射**

至此，如果对虚拟空间已经了解了，那么接下来，作为coder，应该自动把虚拟空间无视掉，因为Linux的目的也是要让更多额进程能享用内存，又不让进程做麻烦的事情，是将虚拟空间和MMU都透明化，让进程（和coder）只需要管对内存怎样使用。

所以现在开始不再强调虚拟空间了。

mmap就是将文件映射到内存上，进程直接对内存进行读写，然后就会反映到磁盘上。

![img](https://pic2.zhimg.com/80/v2-888968f6d713ccdcb5837e2ec85d5565_720w.webp)

- 虚拟空间获取到一段连续的地址
- 在没有读写的时候，这个地址指向不存在的地方（所以，上图中起始地址和终止地址是还没分配给 进程的）
- 好了，根据偏移量，进程要读文件数据了，数据占在两个页当中（物理内存着色部分）
- 这时，进程开始使用内存了，所以OS给这两个页分配了内存（即缺页异常）（其余部分还是没有分配）
- 然后刚分配的页内是空的，所以再将相同偏移量的文件数据拷贝到物理内存对应页上。

原文地址：https://zhuanlan.zhihu.com/p/465336136

作者：linux