iOS底层探索-内存管理理论

1,133 阅读6分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

上一篇文章我们简单介绍了可执行文件Mach-O的结构,本篇我们主要看一些内存的理论知识,从物理内存管理时代开始。

直接物理内存管理

这种加载方式比较简单暴力,当我们打开一个应用的时候会将整个应用都加载到物理内存上去,应用程序访问的是实际的物理内存地址,示意图如下:

物理内存管理示意图.png

这种管理方式挺好理解的,但是会有两个问题:

  • 内存不够用:如上图所示,A、B、C三个应用已经加载到内存了,如果现在我们要加载E应用到内存,此时物理内存的剩下的空间不够就会导致应用E打开失败,必须关闭A、B、C其中一个应用才能正常打开应用E。
  • 应用的安全问题:因为现在应用程序是直接访问物理内存,假如B是一个恶意软件,它就可以通过自己应用的内存地址通过偏移找到应用C访问的内存地址,这样就不能保证应用C的安全。

为了解决内存不够用的问题,提出了分页管理内存的概念,就是把每个应用使用的内存分页管理,每次只是将使用到的加载到内存里,这样就大大增加了内存的利用率,示意图如下:

分页内存管理示意图.png

可以看到采用分页管理的确可以解决内存不够用的问题,同一时间可以有更多的活跃应用,但是这种方式会引起一个新的问题,就是单个应用访问的内存地址不连续,不连续提高了管理的复杂性,应用安全的问题依然存在,所以后面出现了我们现在常用的虚拟内存管理方式。

虚拟内存管理

每个应用运行以后,它将拥有自己独立的虚拟地址空间,这个虚拟地址空间的大小由计算机硬件平台决定,具体说就是由CPU的位数决定的。硬件决定了地址空间的理论上限,注意这里说的是理论上,理论64位的iPhone的虚拟内存地址可以是2^64字节的大小,但是iPhone6s之后的机型的虚拟内存空间大小是4GB(1GB被操作系统使用、3GB应用使用)。

虚拟内存管理大致的示意图如下:

虚拟内存管理示意图.png

可以看到每个应用都有自己独立且连续的虚拟内存空间,虚拟地址通过MMU这个硬件进行映射找到实际的物理地址,达到访问使用物理地址的功能。从程序点击启动,到运行操作系统角度来看一共经历了三件事情:

  • 创建一个独立的虚拟地址空间,实际上只是分配一个页目录就可以,映射关系等后面程序发生页错误的时候再进行设置。
  • 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系,后面我们会提到缺页错误,当发生缺页错误的时候,操作系统将从物理内存中分配一个物理页,然后将该缺页从磁盘中读取到内存中,在设置缺页的虚拟页和物理页的映射关系,这样才能正常运行,这时候就是使用了虚拟空间地址和可执行文件之间的映射关系。
  • 将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。

可以看出虚拟内存同时解决了内存不够用和应用安全的问题,因为每个应用程序是独立的虚拟内存,不能访问其他程序的内存也就达不到攻击的目的。

缺页错误

我们知道采用分页管理的时候,应用程序不是一下在都加载到内存的,当我们访问的数据或指令不在内存里的时候,就需要加载访问数据或指令所在的页,这个情况就要缺页错误(page fault)。

在抖音团队的iOS启动优化《原理篇》,有提到这一点,一次pagefault所消耗的时间是毫秒级别的,但是在我们应用启动的时候会有大量的pagefault,这样我们可以使用二进制重排的方式减少pagefault的次数,从而达到启动优化的目的,感兴趣的同学可以研究一下。

应用虚拟内存空间分布

应用在虚拟内存的分布如下图所示:

虚拟内存区域分布.png

可以看到应用程序能访问到的是五个区域:

  • 代码区(.text):通过镜像文件加载到内存的代码,权限只读,可执行。
  • 已初始化数据(.data):通过镜像文件加载到内存的已经初始化的数据(全局变量、静态变量),权限可读写,可执行。
  • 未初始化数据(.bass):通过镜像文件加载到内存的未初始化的数据(全局变量、静态变量),权限可读写,可执行。
  • 堆区(heap):通过alloc等方法新建的对象所在的区域,我们平时说的ARC的内存管理就是对这个区域的管理,权限可读写,可执行,但是不能通过镜像文件加载恢复,地址向上扩展。
  • 栈区(stack):主要存储是函数、方法以及一些参数,权限可读写,不可执行,不能通过镜像文件恢复,地址向下扩展。 说明:保留区并不是一个单一的内存区域,而是对内存中受到保护二禁止访问的内存区域的总称,例如大部分操作系统,极小的地址通常都是不语序访问的,如NULL。

总结

本篇我们主要介绍了内存的一些理论知识,对目前主流的内存管理方案虚拟内存和应用加载到内存分布的五大区有了一定了解,它对我们理解应用的加载和内存管理的内容有很大帮助,iOS应用的加载流程和内存管理方案在后面的文章中继续探索。