Skip to content

Commit b1fe7d3

Browse files
authored
Create 尽情阅读,技术进阶,详解mmap原理.md
1 parent b9ada50 commit b1fe7d3

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
## 1. 一句话概括mmap
2+
3+
mmap的作用,在应用这一层,是让你把文件的某一段,当作内存一样来访问。将文件映射到物理内存,将进程虚拟空间映射到那块内存。
4+
5+
这样,进程不仅能像访问内存一样读写文件,多个进程映射同一文件,还能保证虚拟空间映射到同一块物理内存,达到内存共享的作用。
6+
7+
## 2. 虚拟内存?虚拟空间?
8+
9+
其实是一个概念,前一篇对于这个词没有确切的定义,现在定义一下:
10+
11+
虚拟空间就是进程看到的所有地址组成的空间,虚拟空间是某个进程对分配给它的所有物理地址(已经分配的和将会分配的)的重新映射。
12+
13+
而虚拟内存,为啥叫虚拟内存,是因为它就不是真正的内存,是假的,因为它是由地址组成的空间,所以在这里,使用虚拟空间这个词更加确切和易懂。(不过虚拟内存这个词也不算错)
14+
15+
### 2.1 虚拟空间原理
16+
17+
#### 2.1.1物理内存
18+
19+
首先,物理地址实际上也不是连续的,通常是包含作为主存的DRAM和IO寄存器
20+
21+
![image](https://user-images.githubusercontent.com/87457873/127429281-171f23f8-7e9c-41da-92d5-1cc1ca388e75.png)
22+
23+
以前的CPU(如X86)是为IO划分单独的地址空间,所以不能用直接访问内存的方式(如指针)IO,只能用专门的方法(in/read/out/write)诸如此类。
24+
25+
现在的CPU利用PCI总线将IO寄存器映射到物理内存,所以出现了基于内存访问的IO。
26+
27+
还有一点补充的,就如同进程空间有一块内核空间一样,物理内存也会有极小一部分是不能访问的,为内核所用。
28+
29+
### 2.1.2三个总线
30+
31+
这里再补充下三个总线的知识,即:地址总线、数据总线、控制总线<br>
32+
* 地址总线,用来传输地址
33+
* 数据总线,用来传输数据
34+
* 控制总线,用来传输命令
35+
36+
比如CPU通过控制总线发送读取命令,同时用地址总线发送要读取的数据虚地址,经过MMU后到内存
37+
38+
内存通过数据总线将数据传输给CPU。
39+
40+
虚拟地址的空间和指令集的地址长度有关,不一定和物理地址长度一致,比如现在的64位处理器,从VA角度看来,可以访问64位的地址,但地址总线长度只有48位,所以你可以访问一个位于2^52这个位置的地址。
41+
42+
#### 2.1.3虚拟内存地址转换(虚地址转实地址)
43+
44+
上面已经明确了虚拟内存是虚拟空间,即地址的集合这一概念。基于此,来说说原理。
45+
46+
如果还记得操作系统课程里面提到的虚地址,那么这个虚地址就是虚拟空间的地址了,虚地址通过转换得到实地址,转换方式课程内也讲得很清楚,虚地址头部包含了页号(段地址和段大小,看存储模式:页存储、段存储,段页式),剩下部分是偏移量,经过MMU转换成实地址。
47+
48+
![image](https://user-images.githubusercontent.com/87457873/127429372-deee3016-bbe6-45d6-a4f5-97c059ec50a7.png)
49+
50+
存储方式
51+
52+
![image](https://user-images.githubusercontent.com/87457873/127429381-f718ed00-3600-4af3-b44b-4ec782ad5efa.png)
53+
54+
如图则是页式存储动态地址变换的方式
55+
56+
虚拟地址头部为页号通过查询页表得到物理页号,假设一页时1K,那么页号*偏移量就得到物理地址
57+
58+
![image](https://user-images.githubusercontent.com/87457873/127429396-c3cde657-870e-4a9e-a945-58639ab59726.png)
59+
60+
如图所示,段式存储
61+
62+
虚拟地址头部为段号,段表中找到段基地址加上偏移量得到实地址
63+
64+
![image](https://user-images.githubusercontent.com/87457873/127429412-b59eddf2-8c13-4f38-822a-445fbbc253b3.png)
65+
66+
段页式结合两者,如图所示。
67+
68+
## 3. mmap映射
69+
70+
至此,如果对虚拟空间已经了解了,那么接下来,作为coder,应该自动把虚拟空间无视掉,因为Linux的目的也是要让更多额进程能享用内存,又不让进程做麻烦的事情,是将虚拟空间和MMU都透明化,让进程(和coder)只需要管对内存怎样使用。
71+
72+
所以现在开始不再强调虚拟空间了。
73+
74+
mmap就是将文件映射到内存上,进程直接对内存进行读写,然后就会反映到磁盘上。
75+
76+
![image](https://user-images.githubusercontent.com/87457873/127429448-ab74f77b-9808-40b4-8a6e-e909a2dd251c.png)
77+
78+
* 虚拟空间获取到一段连续的地址
79+
* 在没有读写的时候,这个地址指向不存在的地方(所以,上图中起始地址和终止地址是还没分配给进程的)
80+
* 好了,根据偏移量,进程要读文件数据了,数据占在两个页当中(物理内存着色部分)
81+
* 这时,进程开始使用内存了,所以OS给这两个页分配了内存(即缺页异常)(其余部分还是没有分配)
82+
* 然后刚分配的页内是空的,所以再将相同偏移量的文件数据拷贝到物理内存对应页上。

0 commit comments

Comments
 (0)