姬長信(Redy)

iOS性能优化系列篇之“优化总体原则”

笔者由于在iOS开发过程中做过一些优化的工作,对iOS性能优化有一些粗浅的认识,一直想把自己这些经验,简单总结一下。于是最近在工作闲暇时间,准备针对iOS开发的性能优化写一系列文章。

作为整个系列的第一篇,我打算针对iOS的优化中的一些总体原则做一些总结。因为我觉得无论列表流畅度优化也好、启动时间优化也好还是说其他方面的优化,都有一些共性的原则,只有掌握了这些总体性的原则,才能够更好的做优化,给我们具体的优化任务指明方向,让我们少绕弯路。后面如果时间允许,我可能会写一些关于列表流畅度、启动时间和内存优化等方面的文章。

在第一篇“优化总体原则”里面。我对优化总体原则总结出包括不要提前过度优化、要找到性能瓶颈、要在不同性能指标间权衡、要理解优化任务的底层运行机制和要有技术保障体系五大原则,其中具体阐述每一个原则的时候并不局限于性能优化方面,会发散到其他的相关领域,会对一些延伸的领域做一些简单的探讨,希望能够对读者有一些启示。以下是第一篇的主要内容。

一、不要提前过度优化

这个原则包括优化的过程中需要避免的两个陷阱,即提前优化和过度优化。

二、要找到性能瓶颈

在做优化前,一定要首先找到性能瓶颈有哪些,依性能严重程度逐个解决。不要盲目优化,否则最后可能花了很大的力气,优化掉的可能只是性能损耗很小的一部分。这一原则我觉得尤为重要,因为我在工作中遇见过包括我在内,很多不进行性能瓶颈查找,全凭主观猜测进行性能优化的情况。 在寻找性能瓶颈过程中,也需要注意以下问题。

  1. 要使用真机,而不是模拟器。模拟器的CPU比iOS机器要快很多,所以在模拟器上,CPU相关的操作会更快。因为Mac的GPU和iOS设备上的GPU不同,所以模拟器需要在CPU上通过软件去模拟iOS设备上的GPU,所以GPU相关的操作会更慢。因此如果使用模拟器去进行性能优化的话,评测设备和真实用户设备性能表现的不一致,会导致优化的效果大打折扣。这里面内存是一个例外,在做内存优化的时候,使用模拟器和真机一般差别不大,可以使用模拟器进行内存的优化。

  2. 要使用Release配置而不是Debug配置,因为在release包的时候,编译器会做一些优化以提高性能。自己的工程代码可能也会在release下做一些优化,比如去除log信息和一些debug功能等。我们关心的是release下的性能,因为用户最终也是使用的release的安装包。所以测试的时候要一定要记住在release配置下进行,instruments进行性能评测的时候,默认是在release下进行的。但是工程代码里面的优化则需要自己注意。笔者就曾经为此付出过很大代价,因为没有注意工程代码里面的一些debug功能,导致优化过程中错误的认为动态库是影响启动时间的罪魁祸首,花了很大力气把动态库修改为静态库,白白浪费了很多时间。

  3. 要使用性能相对差的机器进行评测,因为我们需要保证的是我们的应用在性能差的机器上也有良好的表现。如果有条件,最好能够覆盖多个机型,和我们传统上的认识不同,机型越新性能不一定越高,例如iPad3在动画和渲染性能上比iPad2差。

  4. 要覆盖不同系统版本,因为在iOS系统上,一般系统版本越高,同一机器性能大体上趋于差,所以如果只覆盖低版本的机型,可能在高版本上表现的性能会不尽如人意。

除了使用instruments,还可以使用log等方式进行查找性能瓶颈。

对于线上的App,查找性能瓶颈的工具主要是Application Performance Management(APM)。目前各大公司基本都有自己的APM,主要是对线上App进行性能监控以及预警。因为在开发和测试阶段,由于使用人数相对比较有限,很难覆盖所有的业务场景。而在App发布出去后,大量用户在使用过程中的性能表现,会给我们的App带来更全面的性能评测数据,因此线上App的性能监控是十分重要的。

三、要在不同性能指标间权衡,达到总体最优

在已经找到性能瓶颈的时候,解决性能问题的方法则需要具体问题具体分析,要在不同性能指标间权衡,以达到总体最优。

这需要我们要有整体的意识,App的性能可以分为很多类,不同的性能指标对用户体验造成的影响也不尽相同,比如fps主要影响的是用户的滑动体验,页面加载时间和应用启动时间影响的是用户等待时间上的体验。我们在优化的过程中,要牢记我们的目标是希望App的整体体验最优,而不是某一单项的性能指标最优。不同优化指标之间可能是呈正相关,比如优化了滑动过程中大量函数的耗时时间,使得fps性能提升,可能会导致App的耗电量变少。同时,不同优化指标也可能是负相关、相互制约的,比如为了流畅性做了过多的cache,会导致内存性能下降,甚至导致因为memory warning导致被系统kill掉,这无疑对App的整体体验造成了负面的影响。因此实际优化过程中需要我们反复权衡利弊和取舍,达到整体的性能最优。

四、要理解优化任务的底层运行机制

如果不理解优化任务的底层运行机制,可能很难达到更好的优化效果。

比如在做启动时间优化的时候,如果你不知道iOS中App的启动时间是由main之前和main之后两部分时间组成的,此时如果你的App是因为main函数之前的部分占用了过多的启动时间,可能你花了大量的精力去优化main之后的时间却没有达到好的优化效果。如果你不知道App启动过程的运行机制,就无法知道去检查是否链接了过多的自定义的动态库或者去load函数里面确认是否有耗时的操作等等。还有在做fps优化的时候,如果不了解卡顿的底层原因是什么、一个view从创建到显示过程中经历那些步骤、CPU和GPU在这个过程中都扮演什么角色,则很难做到丝滑般的顺畅?还有在做内存优化的时候,如果不了解内存分为哪几类、系统对App和不同类型extension的内存限制机制的不同、超过限制系统会采取什么操作等等,也很难把内存优化做好。因此只有深入了解底层机制才能更好的有针对性的提出更优的解决方案。

其实不只是在性能优化方面,在开发过程中很多情况下,了解底层的原理会让你变得更高效,更容易解决遇到的各种问题。在这里分享一个我印象比较深的一次经历。记得有一次在开发某个功能的时候,需要用到level db数据库,在开发过程中做单元测试的时候发现,level db的本地存储文件在不断删除和写入的过程中,越变越大,甚至达到1G大小。当时第一印象以为是在使用上出了问题,所以上层业务逻辑上查找问题,结果查了很久都没有找到问题。但如果我在使用level db的时候去多了解一下其底层的实现原理,了解LSM(Log-Structured-Merge Tree)的原理,遇到这个问题的时候就不会认为这是一个bug,也不会浪费了大把的时间来做无用功。所以建议大家不要抱怨每天的工作过于简单枯燥,在开发过程中多去挖掘一些深层次的东西,不但让你的技术的深度不断加深,也会对你的编码效率有很大的提升。

五、要有技术保障体系

性能优化不能一劳永逸,我个人觉得更是一场持久战。不仅需要你能够在某个特定时期做专项优化的攻坚战,还要为打好持久战做出好的后勤补给,为了能使App长期保持好的性能,不仅仅需要开发人员有良好的开发技能,还需要有一些技术保障和体系。下面简单罗列我能想到的几个方面。

以上我对iOS性能优化的总体原则做的总结,希望能够对大家有一点点启示。其中可能很多想法并不成熟,也希望大家能够多多批评互相探讨,共同进步。

作者:Hello_Vicent

链接:https://juejin.im/post/5ac216075188255c93237306

退出移动版