iOS内存管理整理

62 阅读3分钟

1.1 操作系统内存管理路线图

iShot2023-08-18_10.18.00.png

引发的思考:

  • 有哪些特殊的场景,需要MRC自己管理内存计数?
  • 怎么监控项目循环引用?

三方检测工具MLeaksFinder、OOMDetecter等

1.2 描述

  • 系统层级

为什么会出现内存OOM,App被杀死的原因。

多程序多任务执行需要,物理内存不够 => 虚拟内存 => 空间分配更加灵活 => 分段、分页机制 => 内存映射效率的需要 => (DRAM/Jetsam机制)

  • App进程层级

内存布局:代码段、数据段、堆、栈。

变量在堆区动态申请、释放内存空间。=> (1. 申请空间不释放 2. 频繁的动态申请,产生内存碎片,不能及时回收)

以一个自定义的Person类为例,分析其内存布局:
堆内存:
Person类的对象本身会在堆内存中分配,存放对象的元信息,如isa指针、对象地址等。
堆内存中的Person对象存储了指向数据区的指针。
数据区:
Person类中的name、age等属性需要存储数据内容,所以会在数据区单独申请内存块。
数据区中将包含Person对象的name、age等属性内容。
Person对象中的指针指向该数据区。
数据区大小可根据需要动态扩展。
代码访问:
创建Person对象时,会同时在堆区与数据区各自分配内存。
通过Person对象的指针访问name、age等属性,实际是访问数据区。
Person对象本身存储在堆区,属性实际内容存储在数据区。
释放:
释放Person对象时,堆区与数据区相关的内存都会被回收。

引用计数机制:创建变量后,会在App进程对应的内存空间堆区,申请一段内存空间,同时对应一个标识位记录变量引用的次数,如果被变量引用后,则+1,引用的变量释放后,则-1,引用次数为0的话,会释放对于的内存空间。

循环引用问题,A->B, B->C, C->A 导致对应内存空间无法释放,需要拆循环!!!

为了使用方便,引入了weak指针,

  • weak实现原理

A. 引用计数不会加1

B. objc释放以后自动置为nil

weak_table_t哈希表

1.3 OOM崩溃的治理

  • 阀值和时机

获取方式,Jetsam机制,App内存使用阀值为多少,通过系统日志,看需要pageSize * rpages 等于1.4G ;XNU系统entity中获取优先级和内存限制;task_info获取(app内可获取)

怎么触发的呢?

iOS系统启动后,会开启一个vm_pressure_monitor的线程查看系统内存压力;同时通过一个堆栈维护所有的App进程,内存快照表记录各App的内存使用情况。

监控到内存紧张时,就会通知App代理,didReceiveMemoryWarning,给App处理内存释放,否则杀死App进程。

怎么优先级判断呢?

内核>系统进程>前台App>后台App

CPU占用少的>占用多的

App杀死前,至少有6s的实践做优先级判读,并生成JetsamEvent日志。

  • 定位申请者

malloc分配内存时,都会走malloc_logger,所以可以使用fishhook去hook函数掌握内存分配情况。

1.4 内存使用建议

官方使用建议:

iOS开发如何优化内存,iOS Memory Deep Dive - WWDC18 - Videos - Apple Developer

WWDC Session: 图片使用最佳实践

App 低内存状态的处理,No pressure, Mon! Handling low memory conditions in iOS and Mavericks

第三方内存监测工具原理解析

  1. github.com/Tencent/MLe…
  2. github.com/facebook/FB…
  3. github.com/Tencent/OOM…