为什么会有虚拟地址空间?
1.早期的内存分配
假如说有一块物理内存的大小是128M,此时有一个进程A需要需要20M的内存去运行,一个进程B需要100M的内存去运行,这两个进程在内存中是没有隔离的,有些恶意的进程可能会去修改其他的进程,所以这个很不安全的。
假设此时在来一次进程C需要20M的内存去运行,那么此时的物理内存是不够的,那么当时的人是怎么解决的?系统必须选择一个已运行的程序,将该程序运行暂时不需要的数据暂时拷贝到硬盘上,当内存中的剩余空间可以满足程序C的要求后,操作系统会在剩余空间中随机分配一段连续的20M大小的空间给程序C使用,在这个工程中有大量的数据在装入装出,导致效率十分低下,因为是随机分配的,所以程序运行的地址是不确定的。
2、如何实现进程地址空间隔离
在32位的操作系统中,当创建一个进程时,操作系统会为该进程分配一个4GB大小的虚拟进程地址空间。要注意的是这个4GB的地址空间是“虚拟”的,并不是真实存在的,而且每个进程只能访问自己虚拟地址空间中的数据,无法访问别的进程中的数据,通过这种方法实现了进程间的地址隔离。
虚拟内存空间就好比是花呗,花呗的额度比如说是5000,每次使用是用多少借多少,最多可以用5000。
Linux内核将这4GB的空间分为两个部分。最高的1GB(从虚拟地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间“。而较低的3GB(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间”
下图是虚拟空间的构成:
3、如何实现内存地址空间隔离
为了内存地址空间隔离的效果,人们想到了一种变通的方法,就是增加一个中间层,利用一种间接的地址访问方法访问物理内存。按照这种方法,程序中访问的内存地址不再是实际的物理内存地址,而是一个虚拟地址,然后由操作系统将这个虚拟地址映射到适当的物理内存地址上。这样,只要操作系统处理好虚拟地址到物理内存地址的映射,就可以保证不同的程序最终访问的内存地址位于不同的区域,彼此没有重叠,就可以达到内存地址空间隔离的效果。
MMU 的作用:
1. 将虚拟地址翻译成为物理地址,然后访问实际的物理地址
2. 访问权限控制
4、分页
程序的运行在某个时间段内,只是访问程序的一小部分数据,也就是说,程序的大部分数据在一个时间段内都不会被用到。基于这种情况,人们想到了粒度更小的内存分割和映射方法,这种方法就是分页(Paging)。
分页的基本方法是,将地址空间分成许多的页。每页的大小由CPU决定,然后由操作系统选择页的大小。PC上目前都选择使用4KB。按这种选择,4GB虚拟地址空间共可以分成1048576个页,512M的物理内存可以分为131072个页。显然虚拟空间的页数要比物理空间的页数多得多。
在分段的方法中,每次程序运行时总是把程序全部装入内存,而分页的方法则有所不同。分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,然后建立虚拟地址空间中的页和刚分配的物理内存页间的映射。