操作系统笔记之物理内存和虚拟内存
由于操作系统的进程与进程之间是共享 CPU 和内存资源的,因此需要一套完善的内存管理机制防止进程之间内存泄漏的问题。为了更加有效地管理内存并减少出错,现代操作系统提供了一种对主存的抽象概念,即虚拟内存(Virtual Memory)。
虚拟内存为每个进程提供了一个一致的、私有的地址空间,它让每个进程产生了一种自己在独享主存的错觉(每个进程拥有一片连续完整的内存空间)。
物理内存
物理内存(Physical Memory)是相对于虚拟内存(Virtual Memory)而言的。
物理内存指通过物理内存条而获得的内存空间,而虚拟内存则是指将硬盘的一块区域划分来作为内存。内存主要作用是在计算机运行时为操作系统和各种程序提供临时储存。
在应用中,自然是顾名思义,物理上,真实存在的插在主板内存槽上的内存条的容量的大小。
虚拟内存
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间)。而实际上,虚拟内存通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换,加载到物理内存中来。
目前,大多数操作系统都使用了虚拟内存,如 Windows 系统的虚拟内存、Linux 系统的交换空间等等。
虚拟内存地址和用户进程紧密相关,一般来说不同进程里的同一个虚拟地址指向的物理地址是不一样的,所以离开进程谈虚拟内存没有任何意义。每个进程所能使用的虚拟地址大小和 CPU 位数有关。
在 32 位的系统上,虚拟地址空间大小是 2^32=4G,在 64 位系统上,虚拟地址空间大小是 2^64=16G,而实际的物理内存可能远远小于虚拟内存的大小。
每个用户进程维护了一个单独的页表(Page Table),虚拟内存和物理内存就是通过这个页表实现地址空间的映射的。
下面给出两个进程 A、B 各自的虚拟内存空间以及对应的物理内存之间的地址映射示意图:
当进程执行一个程序时,需要先从内存中读取该进程的指令,然后执行,获取指令时用到的就是虚拟地址。
这个虚拟地址是程序链接时确定的(内核加载并初始化进程时会调整动态库的地址范围)。
为了获取到实际的数据,CPU 需要将虚拟地址转换成物理地址,CPU 转换地址时需要用到进程的页表(Page Table),而页表(Page Table)里面的数据由操作系统维护。其中页表(Page Table)可以简单的理解为单个内存映射(Memory Mapping)的链表(当然实际结构很复杂)。里面的每个内存映射(Memory Mapping)都将一块虚拟地址映射到一个特定的地址空间(物理内存或者磁盘存储空间)。
每个进程拥有自己的页表(Page Table),和其他进程的页表(Page Table)没有关系。
通过上面的介绍,我们可以简单的将用户进程申请并访问物理内存(或磁盘存储空间)的过程总结如下:
- 用户进程向操作系统发出内存申请请求。
- 系统会检查进程的虚拟地址空间是否被用完,如果有剩余,给进程分配虚拟地址。
- 系统为这块虚拟地址创建内存映射(Memory Mapping),并将它放进该进程的页表(Page Table)
- 系统返回虚拟地址给用户进程,用户进程开始访问该虚拟地址。
- CPU 根据虚拟地址在此进程的页表(Page Table)中找到了相应的内存映射(Memory Mapping),但是这个内存映射(Memory Mapping)没有和物理内存关联,于是产生缺页中断。
- 操作系统收到缺页中断后,分配真正的物理内存并将它关联到页表相应的内存映射(Memory Mapping)。中断处理完成后,CPU 就可以访问内存了
- 当然缺页中断不是每次都会发生,只有系统觉得有必要延迟分配内存的时候才用的着,也即很多时候在上面的第 3 步系统会分配真正的物理内存并和内存映射(Memory Mapping)进行关联。
在用户进程和物理内存(磁盘存储器)之间引入虚拟内存主要有以下的优点:
地址空间:提供更大的地址空间,并且地址空间是连续的,使得程序编写、链接更加简单。
进程隔离:不同进程的虚拟地址之间没有关系,所以一个进程的操作不会对其他进程造成影响。
数据保护:每块虚拟内存都有相应的读写属性,这样就能保护程序的代码段不被修改,数据块不能被执行等,增加了系统的安全性。
内存映射:有了虚拟内存之后,可以直接映射磁盘上的文件(可执行文件或动态库)到虚拟地址空间。
这样可以做到物理内存延时分配,只有在需要读相应的文件的时候,才将它真正的从磁盘上加载到内存中来,而在内存吃紧的时候又可以将这部分内存清空掉,提高物理内存利用效率,并且所有这些对应用程序都是透明的。
共享内存:比如动态库只需要在内存中存储一份,然后将它映射到不同进程的虚拟地址空间中,让进程觉得自己独占了这个文件。进程间的内存共享也可以通过映射同一块物理内存到进程的不同虚拟地址空间来实现共享。
物理内存管理:物理地址空间全部由操作系统管理,进程无法直接分配和回收,从而系统可以更好的利用内存,平衡进程间对内存的需求。