虚拟内存的出现
- 虚拟内存是由物理内存发展得来,在早期操作系统使用的是物理内存,就是直接把程序直接加载到物理内存里面,就是内存的地址和它真是的地址是一模一样,当加载太多程序的 时候就会出现内存不足的情况,这个时候需要关掉一些程序才能打开现在要打开的程序,而且软件的发展速度远远快于硬件的升级速度,这样直接使用物理内存的缺陷非常明显;
- 同时由于程序上访问的内存地址是真实的地址,这样可以通过内存指针偏移去访问到其他的数据,这样就存在一定的安全风险;
- 另外程序加载后,有许多的内容并不是马上需要用到,只需要加载所需的内容,所以就把内存分为一块一块,加载需要的数据进内存,就设计出了懒加载,当你需要使用的时候才加载进内存里面, 这样就节省了内存,但是这样就衍生出一个新的问题,用户切换不同程序的时候,用户使用这个程序需要把这个程序加载到内存,用另一个程序又需要把程序加到内存,这样就会造成一种现象,一个程序的地址在内存里面是不连续的,这又出现了一个新的情况,系统每次分配空闲内存是随机的,并不知道哪块内存一定对应哪个程序,这样程序运行效率很低,因为系统需要大量计算来确定内存属于哪个程序,系统就会显示出卡顿的现象
由于物理内存存在如此多的缺陷,因此虚拟内存诞生:
虚拟内存的出现,让程序就不直接和物理内存直接关联。计算机领域有一种设计思想,就是计算机科学领域的许多问题都可以通过增加一层中间层来解决。虚拟内存就相当于一层中间层。
如上图所示,系统会为每个程序创建一张虚拟内存地址表,程序创建的时候就不需要考虑物理的内存地址,它都交给CPU新增的硬件来处理,这个硬件就叫MMU,也叫内存管理单元。MMU的任务只有一个,就就是翻译地址。程序执行的时候只会去找虚拟地址,这个时候程序访问的虚拟地址是连续的,而虚拟地址和物理地址的翻译统统交给MMU去处理,把虚拟地址翻译成物理地址,再去物理地址找对应的数据。
一、虚拟地址和物理地址数据如何对应
它们之间的对应关系并不是按每个字节去翻译,而是按一块的数据去翻译,一个块具体有多大,可以打开终端输入:
jonytang@Mac ~ % PAGESIZE
得到
4096
注:也有些人的电脑可能是
16384
4096表示在当前操作系统,每个块的大小是4KB (16384就是16KB,这里默认4KB为标准),这个4096就是内存中的一页,计算机用page来表示,内存的分页就是这么来的,每4KB为一页。
二、分页技术
- 这个分页为了解决程序分段存在的问题,页的大小是固定的,而段是不固定的,由程序本身的大小决定 。
- 假设内存大小是
100M,现在有3个程序A、B和C,分别有30M、40M和50M的大小,假设先加载了A和B,那么C的50M大小超过了内存的余量30M,这样内存就不足以加载C程序,造成了30M的浪费,内存使用率过低,如果要解决该问题,就需要先把最不活跃的程序在内存释放掉,假设是A最不活跃,那就先写进硬盘,然后释放A内存去加载C,但是由于A有几十M,而且是操作硬盘的写入,所以速度会很慢。 - 而分页虽然也存在着内存不足的情况,但是每一页只有
4KB,这个读写进硬盘的速度远高于几十M的程序写进内存;另外由于一页只有4KB,每次按照4KB去取内存写入,这样也不存在一次性有几十M内存浪费的情况。
使用虚拟内存解决了物理内存的一次性加载大块内存的问题,同时也解决了安全问题,如果外部访问了虚拟内存的数据,由于每个进程虚拟内存的数据是独立的,因此是无法通过当前进程的地址去访问其他进程的数据,而进程和进程之间的通信,只能通过系统的接口去访问。
三、缺页中断
假设进程一启动的时候 我们需要加载它的P1、P3和P5 这三页,现在使用P2这一页,而这个时候P2还没有被加载进内存,这个时候就会出现缺页异常也叫缺页中断,这个时候系统会将P2加载到内存里面
四、内存分配原则
内存的分配原则是哪里有空余内存就分配到哪里,如果系统运行了一段时间,内存被使用到占满,这时系统会将不活跃的给释放掉,然后把现在需要用这个的这一页将其加载进内存,这个过程被称为页面置换。这就是手机开启多个程序一段时间后,再点开很久没有打开的应用,会看到该软件的启动界面,就是该进程不活跃,其在内存中的数据被新的应用给覆盖,这就是使用了计算机虚拟内存处理多个进程出现的现象。
五、rebase
接下来是关于rebase,rebase的出现是虚拟内存也存在一个问题,早期使用程序被加载到内存的时候,它的地址是随机的,就是可执行文件数据访问的访问,每次都是随机的。在使用物理地址每次地址随机,它的好处是就是比较安全,可以防止攻击者可以通过有规律的地址来获取一些数据,但是使用虚拟内存每次都是从0开始,虚拟内存的安全性就相对不高,针对这个问题,操作系统使用了一种新的方式来处理,就是ASLR(地址空间随机化)。ASLR让虚拟地址不是从0开始,而是一个随机的值开始,这样程序每次启动的虚拟地址都是随机的。
偏移可以通过一个可执行文件来查看
用MachOView打开,随便选择一个Section64,可以看到偏移Offest
Offest的地址是偏移后的地址,所以需要加ASLR之后才能找到真正的地址,而Offest + ASLR 这个操作就叫rebase。