iOS内存详解之内存相关的概念

高效的内存管理是编写高性能代码的重要方面。最大限度地减少内存使用量不仅可以减少应用程序的内存占用,还可以减少占用的CPU时间。总之好处多多。近段时间都在看内存优化相关方面的东西。花了很多心思和时间,但总感觉收获不大。于是想把最近学习的资料和项目中的经验总结一下写成博客,这样收获更大,将来也方便回过头再看看。鉴于目前的技术水平,文中肯定有很多不对的地方,希望大家指出,一起交流学习。

准备将相关内存关键点分成5篇写成系列叫做iOS内存详解,这篇是系列的开篇iOS内存详解之内存相关的概念。为了正确优化代码使用的内存,我们需要了解底层系统如何管理内存的。首先来看操作系统下内存相关的概念。



一、什么是内存

在计算机组成中,存储器是一个很重要的部分,存储器是用来存储程序和数据的部件,对于计算机来说,有了存储器,才有记忆功能,才能保证正常工作。存储器的种类很多,按其用途可分为主存储器和辅助存储器,主存储器又称内存储器(简称内存)。内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,我们平常使用的程序,如Windows操作系统、打字软件、游戏软件等,一般都是安装在硬盘等外存上的,但仅此是不能使用其功能的,必须把它们调入内存中运行,才能真正使用其功能,我们平时输入一段文字,或玩一个游戏,其实都是在内存中进行的(如下图)。并且在运行时,它们会分配额外的内存(显式和隐式)来存储和操作程序的数据。因此内存的性能对计算机的影响非常大。

内存分布



二、操作系统对内存的管理

操作系统是通过虚拟内存系统来管理内存的,先介绍一下什么事虚拟内存。

1、虚拟内存

虚拟内存允许操作系统逃避物理内存(RAM)的限制。虚拟内存管理器创建一个逻辑地址空间(即“每个进程的虚拟“地址空间”,并将其划分为统一大小的内存块页面。处理器及其内存管理单元(MMU)维护页表将程序逻辑地址空间中的页面映射到内存中的硬件地址。当程序的代码访问存储器中的地址时,MMU使用页表将指定的逻辑地址转换为实际的硬件存储器地址。此转换自动发生,对正在运行的应用程序是透明的。

对于具有4 GB或更多GB可用内存的计算机,系统也很少将这么多内存用于单个进程。为了让进程能够访问其整个4GB或更多的地址空间,操作系统使用硬盘来保存当前未使用的数据。当内存变满时,未使用的内存部分将写入磁盘,以便为现在需要的数据腾出空间。存储未使用数据的磁盘部分称为后备存储,因为它为主存储器提供备份存储。

内存映射

计算机内存大小受限于CPU的寻址能力,这里牵涉到一个概念寻址空间。

2、什么事寻址空间?

寻址空间一般指的是CPU对于内存寻址的能力。通俗地说,就是能最多用到多少内存的一个问题。数据在内存中存放是有规律的 ,CPU在运算的时候需要把数据提取出来就需要知道数据存放在哪里 ,这时候就需要挨家挨户的找,这就叫做寻址,但如果地址太多超出了CPU的能力范围,CPU就无法找到数据了。 CPU最大能查找多大范围的地址叫做寻址能力 ,CPU的寻址能力以字节为单位 ,如32位寻址的CPU可以寻址2的32次方大小的地址也就是4G,这也是为什么32位的CPU最大能搭配4G内存的原因 ,再多的话CPU就找不到了。

内存寻址

3、虚拟内存系统如何影响性能

进程的逻辑地址空间由映射的内存区域组成。每个映射的存储器区域包含已知数量的虚拟存储器页面组成的页面。每个区域都有特定的属性来控制,保护常驻内存不能被分页。常驻内存(Wired Memory)

常驻内存是必须永远不会被分页到磁盘的内核代码和数据结构。应用程序,框架和其他用户级软件无法分配常驻内存。但是,它们可以随时影响常驻内存的存在量。例如,创建线程和端口的应用程序隐式地为与其关联的所需内核资源分配常驻内存。下面列出了常见常驻内存:

常驻内存

这些值和操作系统关联比较大,不是绝对的。操作系统内核本身中的虚拟内存本身也是常驻内存。

系统将物理内存分成三个表并维护他们: 1. 活动页面列表即当前映射到虚拟内存并最近访问过的页面 1. 非活动的页面列表即当前映射到虚拟内存但尚未最近访问过,可以随时删除 1. 空闲页面列表即没有映射到虚拟内存中,可以被需要他们的进程立即使用

当空闲列表上的页数低于阈值(由物理内存大小确定)时,寻呼机会尝试平衡队列。它通过从非活动列表中提取页面来完成此操作。如果最近访问过某个页面,则会重新激活该页面并将其放在活动列表的末尾。在OS X中,如果非活动页面包含最近未写入后备存储的数据,则必须先将其内容分页到磁盘,然后才能将其放在空闲列表中。(在iOS中,已修改但非活动的页面必须保留在内存中,并由拥有它们的应用程序清理。这是因为iOS不支持后备存储。在iPhone应用程序中,磁盘上已有的只读数据(例如代码页)只是从内存中删除,并根据需要从磁盘重新加载。操作系统永远不会从内存中删除可写数据。相反,如果可用内存量低于某个阈值,系统会要求正在运行的应用程序自动释放内存以为新数据腾出空间。无法释放足够内存的应用程序将被终止。这就是我们收到内存警告的原因)如果非活动页面未被修改且未永久驻留(常驻),则它被销毁(任何当前的虚拟映射)并添加到空闲列表中。一旦空闲列表大小超过目标阈值,寻呼机就会休息。 如果不访问页面,内核会将页面从活动列表移动到非活动列表;它会在软故障时将页面从非活动列表移动到活动列表。交换虚拟页面时,关联的物理页面将放置在空闲列表中。此外,当进程显式释放内存时,内核会将受影响的页面移动到空闲列表。

就程序而言,其逻辑地址空间中的地址始终可用。但是,如果应用程序访问当前不在物理RAM中的内存页上的地址时,则会发生页面错误。当发生这种情况时,虚拟内存系统会调用一个特殊的页面错误处理程序来立即响应故障。页面错误处理程序停止当前正在执行的代码,找到物理内存的空闲页面,从磁盘加载包含所需数据的页面,更新页面表,然后将控制返回到程序的代码,然后可以访问内存地址。这个过程被称为寻呼。 如果物理内存中没有可用的空闲页面,则处理程序必须首先释放现有页面以为新页面腾出空间。系统如何处理取决于平台。在OS X中,虚拟内存系统通常将页面写入后备存储。该支持系统是一个基于磁盘的存储库,包含给定进程使用的内存页面的副本。调用将数据从物理内存移动到后备存储寻呼(或“交换”);将数据从后备存储移回物理内存被调用分页(或“交换”)。在的iOS中,没有后备存储,因此页面永远不会被分页到磁盘,但仍然可以根据需要从磁盘中分页只读页面。 在OS X和早期版本的iOS中,页面的大小是4千字节。在的iOS的更高版本中,基于A7和A8的系统将16千字节页面暴露给由4千字节物理页面支持的64位用户空间,而A9系统暴露16千字节页面,由16千字节物理页面支持。这些大小决定了发生页面错误时系统从磁盘读取的千字节数。当系统花费不成比例的时间处理页面错误和读取和写入页面而不是执行程序代码时,会可能发生磁盘抖动。 任何类型的分页,特别是磁盘抖动都会对性能产生负面影响,因为它会迫使系统花费大量时间来读写磁盘。从后备存储中读取页面需要花费大量时间,并且比直接从内存中读取要慢得多。如果系统必须先将页面写入磁盘才能从磁盘读取另一个页面,则性能影响会更大。



三、总结

我们主要通过对一些内存相关的概念的理解,了解内存的作用以及操作系统如何通过虚拟内存系统来管理内存的,知道内存的使用不当影响性能的底层原理。下一篇将要为大家介绍iOS系统下内存的分配以及怎么避免内存性能问题。



参考链接: