仅作为本人学习《深入 C 语言和程序运行原理》的学习笔记,原课程链接:极客时间《深入 C 语言和程序运行原理》——于航
本讲主要介绍了进程是如何在操作系统的控制下与计算机内存交互的。
计算机内部的缓存系统虚拟内存机制计算机上的 CPU 需要不断处理电脑硬盘上的数据,但是 CPU 速度太快,动辄几 GHz,而硬盘速度太慢,传输速度才不到 200MB/s,延时还大,即使是固态硬盘也差的很远,完全无法跟上 CPU 的处理速度,这样必然会导致性能下降。
于是工程师就在 CPU 中设计了缓存,一二三级缓存充当了数据临时仓库的作用,而且速度很快,但是受限于成本和 CPU 面积,这个缓存空间有限,根本放不了多少数据,于是就在 CPU 缓存和硬盘之间又加入了新的存储器:内存。
内存速度和成本都介于 CPU 缓存和硬盘之间,容量也更容易扩充,于是成为了非常合适的数据桥梁。这样电脑的操作系统在运行一个程序的时候,会把要用到的数据先写入到内存,因为内存上的数据读取的延迟比硬盘少得多,所以速度快得多,能够更快地把数据交给 CPU 来处理,同时内存也能靠大容量临时存储一些常用数据,这样大大加快了电脑的运行效率。
如果内存不够的话,电脑就要把这些数据读取到硬盘的一块区域(叫虚拟内存),虚拟内存是在硬盘上的,速度慢得多,因此当电脑物理内存不够的时候会大幅度降低速度。——百度知道
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。
——百度百科
虚拟内存是由操作系统抽象出来的一个概念,它在物理内存的基础上进行了一层抽象。因此,我们在应用程序打印的各种指针值,实际上都对应于虚拟内存中的某个地址,而非实际物理地址。这些程序的虚拟地址构成了虚拟地址空间(VAS)。
CPU 在访问内存中的数据时,会借助其芯片上名为 “内存管理单元(MMU)”的硬件,首先将虚拟地址动态翻译为对应的物理地址,然后再进行实际的数据获取。
虚拟内存机制的一个最重要特征,就是为每一个应用程序都抽象出了独立于物理内存的虚拟地址空间。
VAS 中的数据布局下图是 Linux 进程在 VAS 内的统一数据布局结构。
Linux 进程 VAS 中的数据,按照地址由低到高的顺序,可以被分为下面这几个部分。
- LOAD Segments: 这部分数据被加载到从地址 0x400000 开始的虚拟内存中。其主要内容为应用程序 ELF 二进制文件内定义的各种 LOAD Segment 结构。
- 堆:用于存放进程运行时动态分配的内存。随着动态数据的不断产生,它将向 VAS 的高地址方向不断增长。
- 共享库数据:这部分内存中包含有与各类 .so 共享库相关的数据,程序会在运行时通过动态链接器来完成对它们的加载和处理。
- 栈:记录函数调用过程相关的维护性信息,随着各种局部变量的不断产生,它将向 VAS 的低地址方向不断增长。
- 用于系统调用加速的内核数据:
- 其他内核数据:在进程 VAS 的高地址处,还可能包含与当前进程相关的各种数据结构。
借助虚拟内存机制,不同进程之间可以共享物理内存上的同一段数据。这些数据在物理内存中实际存放时,可能并不是连续的。而借助于页表实现的 “虚拟页与物理页映射关系分离”,我们可以确保 CPU 能够按照连续的方式来使用这些数据。
当某个共享进程试图对这些共享数据进行修改时,操作系统会通过 “写时复制(Copy-on-write)” 的方式,来将被变更数据所在的物理页进行复制,并通过修改页表,来让修改进程可以私有化这部分数据。



