iOS 内存监控与治理(二)-- iOS 内存机制与内存管理

上一章节我们认识了计算机中的内存相关知识,本章节我们整理一些 iOS中内存需要关注的点以及 iOS 的内存管理。

关于虚拟内存系统

iOS 包含一个完全集成的虚拟内存系统,这个虚拟内存系统是无法关闭的,会一直开启。这个虚拟内存系统可以为每个32位进程提供4GB的可寻址空间。

虚拟内存管理器会创建一个逻辑地址空间(或虚拟地址空间)用于每个进程(APP),并将其划分为大小均匀的内存块,称为页。早期的版本,页面大小是4kb,A9系统之后,每页大小为16kb。MMU 负责虚拟地址和物理地址的转换。

低内存警告

当iOS 遇到内存不足时,系统可能会向当前运行中的APP发送低内存警告。APP在接收到低内存警告时,应该及时做出响应,尽可能的释放未在使用的内存对象。

OOM

如果在收到低内存警告时,未能释放足够多的内存资源,那么系统可能会杀死一个或多个APP,这就会产生所谓的OOM(out-of-memory)崩溃。oom发生时从现象上看,与普通的Crash 并无区别,只是无法像监控Crash那样监控到OOM崩溃。不过在发生OOM崩溃后,当前设备的设置-隐私-分析与改进中会生成 JetsamEvent开头的日志。

iOS 内存占用

当内存不足的时候,系统会按照一定策略来腾出更多空间供使用,比较常见的做法是将一部分低优先级的数据挪到磁盘上,这个操作称为 Page Out。之后当再次访问到这块数据的时候,系统会负责将它重新搬回内存空间中,这个操作称为 Page In

然而对于移动设备而言,频繁对磁盘进行IO操作会降低存储设备的寿命。从 iOS7 开始,系统开始采用压缩内存的办法来释放内存空间,被压缩的内存称为 Compressed Memory。下面依次介绍一下 iOS App 通常情况下的三种内存类型:Clean MemoryDirty Memory以及Compressed Memory

Clean Memory

可以简单理解为能够被重新写入数据的干净内存。对开发者而言是read-only,而iOS系统可以写入或移除。

  1. System Framework、Binary Executable占用的内存

  2. 可以被释放(Page Out,iOS上是压缩内存的方式)的文件,包括内存映射文件Memory mapped file(如image、data、model等)。内存映射文件通常是只读的。

  3. 系统中可回收、可复用的内存,实际不会立即申请到物理内存,而是真正需要的时候再给。

  4. 每个framework都有DATA_CONST段,当App运行时使用到了某个framework,该framework对应的DATA_CONST的内存就由clean变为dirty了。

注意:如果通过文件内存映射机制memory mapped file载入内存的,可以先清除这部分内存占用,需要的时候再从文件载入到内存。所以是Clean Memory。

Dirty Memory

Dirty Memory 是指那些被 App 写入过数据的内存,包括所有堆区的对象、图像解码缓冲区,同时,类似 Clean memory,也包括 App 所用到的 frameworks。每个 framework 都会有 _DATA 段和 _DATA_DIRTY 段,它们的内存是 Dirty 的。

值得注意的是,在使用 framework 的过程中会产生 Dirty Memory,使用单例或者全局初始化方法是减少 Dirty Memory 不错的方法,因为单例一旦创建就不会销毁,全局初始化方法会在 class 加载时执行。

Compressed Memory

当内存吃紧的时候,系统会将不使用的内存进行压缩,直到下一次访问的时候进行解压。

例如,当我们使用 Dictionary 去缓存数据的时候,假设现在已经使用了 3 页内存,当不访问的时候可能会被压缩为 1 页,再次使用到时候又会解压成 3 页。

iOS 内存管理

iOS 采用引用计数(Reference Count)作为对象的内存管理方式,在当前的Swift和OC工程中,默认使用ARC(Automatic Reference Count)。我们可以在 Build Setting:Apple Clang - Language - Objc查看当前APP是否打开了ARC。此外,在Build Phases:Compile Sources 中为单个文件配置是否打开ARC。

引用计数

引用计数是一种对象生命周期的管理方式。当创建一个对象时,它的引用计数初始化为1,如果有新的指针指向这个对象时,它的引用计数加一,当然如果这个指针不再指向这个对象,那么引用计数就会减一。当对象的引用计数为0时,系统将该对象销毁并回收内存。

ARC与MRC

我们知道早期的iOS 开发是需要研发人员自己手动管理引用计数的,也就是MRC。在2011年之后,苹果推出了自动引用计数 - ARC,ARC的原理是依赖编译器的静态分析能力,在编译时于合适的位置插入引用计数管理代码。

虽然ARC能够帮助我们解决绝大部分场景下的内存问题,但是在实际研发中,还是有一些场景需要研发人员手动管理。

  • 循环引用
  • 与底层 Core Foundation 对象交互
循环引用

两个对象相互引用或者多个对象形成环状引用,都会产生循环引用,导致对象无法正常的释放。比如A控制器,持有一个Block - B,该B内又引用了A控制器的某个属性,这样就导致了A与B的循环引用。循环引用可以通过弱引用(weak reference) 的方式来打破循环引用。所谓弱引用就是持有对象的同时,且不增加引用计数。

弱引用的实现原理

弱引用的实现原理是这样,系统对于每一个有弱引用的对象,都维护一个表来记录它所有的弱引用的指针地址。这样,当一个对象的引用计数为 0 时,系统就通过这张表,找到所有的弱引用指针,继而把它们都置成 nil。

从原理上看,弱引用的使用是有额外的开销,不建议在项目中无脑使用弱引用。

与底层 Core Foundation 对象交互

由于 Core Foundation 对象底层是通过MRC的方式来管理生命周期,所以我们在使用的过程中,还是需要自己手动管理。小技巧:底层的Core Foundation对象创建时大多是以XxxCreateXxx,XxxCreateWithXxx的方式使用的。

// 创建一个 Core Foundation 对象
CTFontRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, nil);

// 引用计数加 1
CFRetain(src);
// 引用计数减 1
CFRelease(src);

此外,在涉及到Core Foundation对象与OC对象转换时,需要引入bridge关键字。

  • __bridge: 只做类型转换,不修改相关对象的引用计数,原来的 Core Foundation 对象在不用时,需要调用 CFRelease 方法。
  • __bridge_retained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对象在不用时,需要调用 CFRelease 方法。
  • __bridge_transfer:类型转换后,将该对象的引用计数交给 ARC 管理,Core Foundation 对象在不用时,不再需要调用 CFRelease 方法。
    参考:

https://juejin.cn/post/6844904056863850504

https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MemoryAlloc.html#//apple_ref/doc/uid/20001881-107791

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容