IOS——Memory 温故而知新

首先说明一下写这篇文章的目标:

  • 1.希望通过对内存更深入的理解解决一些内存相关的crash(研究一下腾讯开源的OOMDetector)
  • 2.对内存相关的知识做一个总结笔记
  • 3.温故而知‘错’ 温习的过程中也许会发现以前的一些理解上的错误 及时改正

iOS 内存机制

对于我们的 App 所依赖的设备而言,内存资源是有限的。降低 App 所使用的内存可以提高性能和体验,相反,过大的内存占用可能会导致 App 被系统强制退出。所以每个 iOS 开发者都应该关注内存问题。我们需要明确的是,这里的减少内存指减少 iOS App 的虚拟内存(Virtual Memory) 占用。

Pages Memory

首先理解一下内存页的概念,现代操作系统将内存划分为页,来简化内存管理,一个页其实就是一段连续的内存地址的集合,通常有4k和16k(iOS 64位是16K)的,成为 Virtual Page 虚拟页。与之对应的物理内存被称为Physical Page 物理页。内存页按照各自的分配和使用状态,可以被分为CleanDirty 两类。

  • 当这些内存页开辟出来的时候,它们都是 Clean 的

  • 当向处于某一页的内存写入数据时,这一页内存会变成 Dirty。

  • 如果是只读的文件,它所占用到的内存页是 Clean 的。 除了以上两种,iOS7开始,系统开始采用压缩内存的办法来释放内存空间,当内存吃紧的时候,系统会将不使用的内存进行压缩,直到下一次访问的时候进行解压,被压缩的内存称为 Compressed Memory。 总结: 1.Clean - Data that can be paged out of memory 指的是能够被系统清理出内存且在需要时能重新加载的数据,包括:

  • Memory mapped files

  • Frameworks 中的 __DATA_CONST 部分

  • 应用的二进制可执行文件

2.Dirty - Any memory that has been written to by your app 指的是不能被系统回收的内存占用,包括

  • 所有堆上的对象
  • 图片解码缓冲数据(Decoded image buffers)
  • Frameworks 中的 __DATA 和 __DATA_DIRTY部分

3.Compressed Memory本质上也是Dirty memory。

所以我们开发人员可以去优化减少的内存占用就是Dirty和Compressed两部分

Tools for profiling footprint

为了更好的找到可以优化的内存占用,Xcode提供了一系列工具帮助开发人员进行debug

  • Xcode memory gauge
  • Allocations
  • Leaks
  • VM Tracker
  • Debug memory graph

Debug memory graph

虽然可视化工具已经能够直观的表现我们想要了解的内存占用信息,但是在终端中不仅可以灵活地利用各种命令和 flag 突出我们想要的内容,更可以快速的实现信息查找和文本化交互。其实我还是本着对未知工具体验尝试的目的,去学习一下

  • 通过Xcode配置(Product —> Scheme — > Edit Scheme)
  • 开启内存图调试器
  • 导出memgraph 文件 File->Export Memory Graph
  • vmmap 命令 查看详细报告

vmmap /Users/suanle/Desktop/BWCMTApp.memgraph

查看摘要报告

vmmap --summary /Users/suanle/Desktop/BWCMTApp.memgraph

查看vmmap更多使用文档

man vmmap

查看内存泄漏

leaks /Users/suanle/Desktop/BWCMTApp.memgraph

查看leaks更多使用文档

man leaks

查看堆区内存

heap /Users/suanle/Desktop/BWCMTApp.memgraph

查看内存分配历史

malloc_history /Users/suanle/Desktop/BWCMTApp.memgraph

iOS 内存管理

iOS中一个APP就是一个进程,开发人员需要关注的内存管理,比如MRC,ARC,实际上都属于进程内部的内存管理,对于开发人员大多数时候还是从语言层面(代码层面)对内存进行操作。

引用计数

引用计数方式最基本的形态就是让每个被管理的对象与一个引用计数器关联在一起,该计数器记录着该对象当前被引用的次数,每当创建一个新的引用指向该对象时其计数器就加1,每当指向该对象的引用失效时计数器就减1。当该计数器的值降到0就认为对象死亡。每个计数器只记录了其对应对象的局部信息——被引用的次数,而没有(也不需要)一份全局的对象图的生死信息。由于只维护局部信息,所以不需要扫描全局对象图就可以识别并释放死对象;但也因为缺乏全局对象图信息,所以无法处理循环引用的状况。更高级的引用计数实现会引入“弱引用”的概念来打破某些已知的循环引用。

总结:引用计数的优点:对象生命周期结束时,可以立刻被回收,而不需要等到全局遍历之后再回收 缺点:循环引用,所以需要开发人员在编码的时候格外注意

OOM (Out of Memory Crash)

Jetsam 机制

iOS 是一个从 BSD 衍生而来的系统,其内核是 Mach。其中内存警告,以及 OOM 崩溃的处理机制就是 Jetsam 机制,也被称为 Memorystatus。Jetsam 会始终监控内存整体使用情况,当内存不足时会根据优先级、内存占用大小杀掉一些进程,并记录成 JetsamEvent。 这里可以查看apple 开源的内核代码

触发didReceiveMemoryWarning

而如何监控内存警告,以及处理 Jetsam 事件呢?首先,内核会调起一个内核优先级最高的线程 这个线程会维护两个列表,一个是基于优先级的进程列表,另一个是每个进程消耗的内存页的列表。与此同时,它会监听内核 pageout 线程对整体内存使用情况的通知,在内存告急时向每个进程转发内存警告,也就是触发 didReceiveMemoryWarning 方法。

触发Out of Memory Crash

而杀掉应用,触发 OOM,主要是通过 memorystatus_kill_on_VM_page_shortage,有同步和异步两种方式。同步方式会立刻杀掉进程,先根据优先级,杀掉优先级低的进程;同一优先级再根据内存大小,杀掉内存占用大的进程。而异步方式只会标记当前进程,通过专门的内存管理线程去杀死。

检测OOM

OOM 分为两大类,Foreground OOM / Background OOM,简写为 FOOM 以及 BOOM。而其中 FOOM 是指 app 在前台时由于消耗内存过大,而被系统杀死,直接表现为 crash。

腾讯开源的 OOMDetector,通过 malloc/free 的更底层接口 malloc_logger_t 记录当前存活对象的内存分配信息,同时也根据系统的 backtrace_symbols 回溯了堆栈信息。之后再根据伸展树(Splay Tree)等做数据存储分析。

OOM常见原因

  • 循环引用 比较容易出现互相引用的地方是block里使用了self,而self又持有这个block,只能通过代码规范来避免。
  • UIWebView 无论是打开网页,还是执行一段简单的js代码,UIWebView都会占用APP大量内存。而WKWebView不仅有出色的渲染性能,而且它有自己独立进程,一些网页相关的内存消耗移到自身进程里,最适合取替UIWebView。
  • autoreleasepool 通常autoreleased对象是在runloop结束时才释放。如果在循环里产生大量autoreleased对象,内存峰值会猛涨,甚至出现OOM。适当的添加autoreleasepool能及时释放内存,降低峰值。
  • 大图片 大视图渲染

我们的照片主要有四类来源

  1. Image Assets
  2. Bundle,Framework 里面的图片
  3. 在 Documents, Caches 目录下的图片
  4. 网络下载的数据

如果我们想要自己创建Image Buffers,苹果的建议是使用UIGraphicsImageRenderer,因为它的性能更好,还支持广色域。这个东西简单了解了一下,性能虽好,但是实用性差,平时开发中需要自己创建image的场景很少,所以就不多介绍了。

留一个思考问题:对于 iOS 系统而言,绝大部分场景下哪类数据占内存最多呢?当然是图片!所以对于图片的使用,我们有哪些可以优化内存占用的方案呢???

作为一个开发者,有一个学习的氛围和一个交流圈子特别重要,这是我的交流群(123),大家有兴趣可以进群里一起交流学习!

收录:原文地址

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