iOS 内存管理

析构检测原理

几种常见错误会造成内存泄漏

1 使用c语言方法,需要手动释放
2 对文件进行操作,要手动关闭
3 调用block时,给block传指nil
4 数组中插入了nil元素
....

日常项目中常用的内存泄漏检测:

1 静态检测,使用Xcode,Product->Analyze静态分析
2 动态检测,使用Intruments->Leaks动态分析
3 析构检测,通过Runtime(AOP)监听系统dealloc方法


控制器正常的生命周期中会在viewDidDisappear:之后执行dealloc方法,从而进行内存的回收和释放。但是如果控制器中存在循环引用之类的问题,会导致控制器的dealloc方法无法执行,造成内存泄漏。
析构检测的原理就是监听控制器的生命周期,在viewDidDisappear:时手动模拟dealloc方法,延迟检测控制器有没有被回收。



iOS App 启动时间优化【main函数、二进制重排、PGO】

1、main函数

1.1pre-main 耗时检测

操作路径:Edit Scheme -- 选择一个Scheme(比如:Run)-- 选择Arguments -- Environment Variables -- 点击添加 -- 设置nameDYLD_PRINT_STATISTICS value : ${DEBUG_ACTIVITY_MODE}

Total pre-main time: 1.2 seconds (100.0%)
         dylib loading time: 670.28 milliseconds (54.7%)
        rebase/binding time:  46.92 milliseconds (3.8%)
            ObjC setup time: 105.55 milliseconds (8.6%)
           initializer time: 400.72 milliseconds (32.7%)
           slowest intializers :
             libSystem.B.dylib : 411015771.6 seconds (107844210.9%)
    libMainThreadChecker.dylib :  43.99 milliseconds (3.5%)
  libViewDebuggerSupport.dylib :  37.72 milliseconds (3.0%)
                     xxx : 575.47 milliseconds (47.0%)
  • dylib loading :加载可执行文件(App 的.o 文件的集合), 加载动态链接库;
  • rebase/binding :对动态链接库进行 rebase 指针调整和 bind 符号绑定;
  • Objc setup :Objc 运行时的初始处理,包括 Objc 相关类的注册、category 注册、selector 唯一性检查等;
  • initializer:包括了执行 +load() 方法、attribute((constructor)) 修饰的函数的调用、创建 C++ 静态全局变量

优化~

  • 减少动态库的个数,如果太多就使用合并的方式控制,这样可以节约dylib loadingrebase/binding的时间
  • 清理项目中未使用到类、类别等,节约objc setup的时间
  • 对于可以不在+load中处理的逻辑放到其他的函数中处理,如:+initialize;控制C++ 全局变量的数量;节约initializer时间

2、二进制重排

2.1 二进制重排,主要是优化我们启动时需要的函数非常分散在各个页,启动时就会多次Page Fault造成时间的损耗
2.2 Page Fault

传送门--

进程如果能直接访问物理内存无疑是很不安全的,所以操作系统在物理内存的上又建立了一层虚拟内存。为了提高效率和方便管理,又对虚拟内存和物理内存又进行分页(Page)。当进程访问一个虚拟内存Page而对应的物理内存却不存在时,会触发一次缺页中断(Page Fault),分配物理内存,有需要的话会从磁盘mmap读人数据。
通过App Store渠道分发的App,Page Fault还会进行签名 验证,所以一次Page Fault的耗时比想象的要多。

  • 启动Instruments
    使用Xcode选择要检测的app,Cmd+i(Profile),启动Instruments
  • 选择System Trace,点击Choose
System Trace ~~~

这里就有疑问了,app首次打开的时候Page Fault的次数很多,打开之后再打开的话就比较少,当打开多个其他app的时候,在打开检测的app发现也会有不少Page Faults

这是由于操作系统的机制,当应用杀掉了,他所访问的物理内存不是立马就清空;它所访问的物理内存,需要通过其他app申请开辟覆盖释放掉,可以通过多打开几个应用来验证发现Page Fault次数变多了的。

2.3 重排

编译器在生成二进制代码的时候,默认按照链接的Object File(.o)顺序写文件,按照Object File内部的函数顺序写函数。编译器在生成二进制代码的时候,默认按照链接的Object File(.o)顺序写文件,按照Object File内部的函数顺序写函数。

静态库文件.a就是一组.o文件的ar包,可以用ar -t查看.a包含的所有.o

简化问题:假设我们只有两个page:page1/page2,其中绿色的method1和method3启动时候需要调用,为了执行对应的代码,系统必须进行两个Page Fault。

但如果我们把method1和method3排布到一起,那么只需要一个Page Fault即可,这就是二进制文件重排的核心原理

2.4 Xcode配置Order

Xcode使用的链接器件是ld,ld有一个不常用的参数-order_file,通过man ld可以看到详细文档:

Alters the order in which functions and data are laid out. For each section in the output file, any symbol in that section that are specified in the order file file is moved to the start of its section and laid out in the same order as in the order file file.

可以看到,order_file中的符号会按照顺序排列在对应section的开始,完美的满足了我们的需求。

Xcode的GUI也提供了order_file选项:

如果order_file中的符号实际不存在会怎么样呢?

ld会忽略这些符号,如果提供了link选项-order_file_statistics,会以warning的形式把这些没找到的符号打印在日志里。

2.4.1 首先打开Write Link Map File查看

Link Map File中文直译为链接映射文件,它是在Xcode生成可执行文件的同时生成的链接信息文件,用于描述可执行文件的构造部分,包括了代码段和数据段的分布情况
我们可以在Xcode的配置中将Write Link Map File设置为YES来生成Map File

可以选中app,Show In Finder -- 找到build目录 -- 按照下面的举例的路径就可以找到:
2.4.2 将load方法设置order再看看Map File
  • 新建xxx.order文件
  • Xcode的Build Setting中设置Order文件

讲述了如何使用order,具体的细节、原理和实践可以参照抖音二进制重排实践;他们的数据是启动优化了15%。

3. PGO

Profile Guided Optimization简称PGO,这个也是LLVM提供的一个优化,我们可以直接在Xcode中进行配置;它是一种改进应用程序的编译器优化的方法。PGO利用应用程序的特殊工具构建来生成有关最常用代码路径和方法的配置文件信息。然后,编译器使用此配置文件信息将优化工作集中在最常用的代码上,从而利用有关程序通常如何表现的额外信息来更好地完成优化工作

配置文件引导式优化(PGO)是一项高级功能,可让您从应用中获取所有性能的最后一点点。它并不难使用,但是需要一些额外的构建步骤和一些注意事项来收集良好的配置文件信息。根据您应用程序代码的性质,PGO可以将性能提高5%到10%,但并非所有应用程序都会从​​中受益。如果您对性能敏感的代码需要进行额外的优化,则PGO可以提供帮助。

原理上简单说如下:

编译一个所有方法插桩了的可执行文件,
运行可执行文件(启动一次app),此时插桩的方法会把执行过的方法都记录下来,并记录方法的执行频率。例如下图的profdata文件。
重新build(原则上只是链接时需要profdata),让链接器按照profdata的信息把(启动中用到的、或者频率高的方法)放到一起。
此时这个新的可执行文件就完成了二进制文件重排,减少了page交换(加载)的次数,提高了系统加载和运行app二进制文件的IO性能,加快了执行速度;这个相比较order的方式,这个优化还考虑了函数调用频率的问题

  • Xcode配置
    打开Use Optimization Profile
  • 选择Action生成Profile

PGO也是官方提供的一个优化手段,具体细节可以参照苹果官方文档:Xcode Profile Guided Optimization;对于有多大的提升我这边跑了几次发现每次数据都有些出入,加上demo比较小,看着也不是很明显,感兴趣的可以在自己的项目中使用这项LLVM的优化

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

推荐阅读更多精彩内容

  • 主要内容: AutoreleasePool简介 AutoreleasePool底层原理 Autorelease与N...
    梧雨北辰阅读 8,018评论 7 40
  • 对于iOS App的首次启动优化,主要关注两个点,一个是main之前的耗时,一个就是main函数到root VC ...
    jayhe阅读 7,051评论 7 32
  • 一、为什么要内存管理 不同的系统版本对 App 运行时占用内存的限制不同,系统版本的升级也会增加占用的内存,同时 ...
    lymdd阅读 1,628评论 0 4
  • 1.weak的实现原理?SideTable的结构是什么样的 weak:其实是runtime全局维护的一个hash表...
    6ffd6634d577阅读 1,051评论 0 2
  • iOS内存分区 栈区,内存管理由系统负责,一个线程对应一个栈区,服从先进后出原则 堆区,内存管理由程序员负责...
    豆大大阅读 313评论 0 3