再探 OSX / iOS 的内存管理
内容提要
本文介绍了iOS/OS X内存管理的概念和知识点,包括虚拟内存、页面错误、页面换出和换入、内存抖动、页面列表、清除内存和脏内存、压缩内存、内存分类、内存分配和释放、内存初始化、内存复用、大内存块申请、批量小内存申请和内存懒复制等。
延伸解读
iOS 与 OS X 内存管理的关键差异
文章指出,iOS 没有磁盘备份存储区,因此页面从不交换到磁盘,但只读页面仍可按需从磁盘换入。而 OS X 会将不活跃页面换出到备份存储区。这一差异直接影响内存回收策略:在 iOS 上,已修改但处于 Inactive 状态的页面必须保留在内存中,由拥有它们的进程负责清理,系统无法像 OS X 那样直接换出脏页。
内存分类对开发者的实际意义
文章将内存分为 Clean Memory 和 Dirty Memory。Clean Memory 可被重新创建或从磁盘恢复,如应用二进制、未使用的 _DATA_CONST 段、mmap 内存页等;Dirty Memory 则是被写入过的内存,包括堆对象、图像解码缓冲区等。在 iOS 上,系统内存吃紧时会先回收 Clean 页,若 Dirty Memory 过多则可能终止进程,因此减少不必要的 Dirty 内存是优化重点。
压缩内存与内存占用评估
iOS 7 后引入 Compressed Memory 机制,对一段时间未访问的 Dirty 页进行压缩,再次访问时解压。系统判断是否警告或终止应用时,依据的是 Dirty Memory 与 Compressed Memory 之和,即 Memory Footprint。这意味着即使部分脏页被压缩,它们仍计入应用的内存占用,开发者需关注整体 Footprint 而非仅物理内存。
高效内存分配的实践要点
文章建议:延迟分配内存以节省启动时间,但释放应尽早;使用 calloc 替代 malloc+memset,因为 calloc 在真正访问时才初始化物理页;复用临时内存,可借助线程局部存储;大块内存用 vm_allocate,小块用 malloc,批量小内存用 malloc_zone_batch_malloc;大内存复制可考虑 vm_copy 实现懒复制。这些方法旨在减少内存压力与提升性能。
Q&A
虚拟内存的概念是什么?
虚拟内存允许操作系统突破物理内存的限制,为每个进程创建独立的逻辑地址空间,并将其分成大小均匀的内存块,称为页面。
页面错误是如何发生的?
页面错误发生时,虚拟内存系统会产生缺页中断,加载所需数据的页面,并更新页表以允许程序正常访问内存地址。
内存抖动是什么?
内存抖动是由于频繁的内存交换导致的性能下降现象,表现为系统花费过多时间处理缺页中断而不是执行用户进程代码。
如何高效进行内存分配?
可以使用懒加载内存、calloc函数进行内存分配、复用临时内存和选择合适的内存分配方式来提高内存分配的效率。
清除内存和脏内存有什么区别?
清除内存是未被修改的内存页,可以被交换到磁盘;脏内存是被进程修改过的内存页,不能被交换。
如何处理过多的脏内存?
在iOS7之后,引入了Compressed Memory机制,通过压缩未被访问的脏内存页来释放内存空间。