关于内存的几个小概念

1. 后备存储(backup storage)

在macOS中,使用磁盘来保存当前未使用的数据。当内存已满时,未使用的内存段会被写入磁盘,为当下需要的数据腾出空间。存储未使用数据的磁盘部分称为后备存储

然而iOS并不支持后备存储。在iPhone应用程序中,已经存在于磁盘上的只读数据只是简单地从内存中移除,并根据需要从磁盘重新加载。操作系统永远不会把可写数据从内存中移除。相反,如果空闲内存低于某个阈值时,系统会要求正在运行的应用程序自动释放内存,为新数据腾出空间。无法释放足够内存的话,应用程序将被终止。

2. 页(page)

为了摆脱物理内存(RAM)的限制,虚拟管理器为每个进程创建一个逻辑地址空间(也叫虚拟地址空间),并将其划分为大小相同的内存块,称之为。物理内存也会被划分为大小相同的页。在macOS和iOS早期版本中,一个页大小是4KB,而在iOS的后续版本中,页大小扩大到了16KB。可通过函数getpagesize()获取页大小。

3. 页入/页出(page-in/page-out)

将数据从物理内存移动到后备存储称为页出(或“换出”);而将数据从后备存储移回到物理内存称为页入(或“换入”)。在iOS中,没有后备存储,因此页永远不会被换出到磁盘,但是只读页仍然可以根据需要从磁盘换入。

4. 页错误 (page-fault)

CPU及其MMU(内存管理单元)维护了一个页表,用于将程序的虚拟地址空间中的页,映射到物理内存中,当程序代码访问内存中的地址时,MMU使用页表将指定的虚拟地址转换为实际的物理内存地址。如果应用程序访问某一内存地址,发现该地址所在的页并没有加载到物理内存中时,就会发生页错误。此时,虚拟内存系统会调用page-fault handler来立即响应错误,page-fault handler会停止当前正在执行的代码,然后在物理内存中分配一个物理页,将该“错误页”所对应的数据从磁盘加载到内存中(Tip1:),接着更新页表,即设置虚拟页和物理页的映射关系,最后将控制权返回给程序的代码,从刚才页错误的位置重新开始执行。

Tip1: 因为可执行文件跟虚拟地址空间的映射关系,所以page-fault handler知道该“错误页”在可执行文件中的位置,也就能在磁盘中找到该页所对应的数据。

关于可执行文件、虚拟地址空间、物理内存三者之间的映射关系,如下图:

映射关系

5. 页类型(page types)

页的类型分为clean和dirty。基于只读文件被加载到内存中的page即为clean,比如:framework中__DATA_CONST部分、可执行文件、以及其他通过mmap映射到内存的文件。由于这种page是加载只读文件,因此可以在物理内存紧张时被iOS卸载,并且之后可根据需要重新加载到内存。除clean page之外,其他都是dirty page。它们的共同点是在磁盘中没有对应的文件,比如:malloc出的内存(堆上的对象)、图片解码缓冲数据等。

关于内存占用,附一张WWDC视屏截图:


参考资料:https://developer.apple.com/Articles/AboutMemory.html

最后更新: 2/1/2021, 5:39:58 PM