内存泄露检测:
1. Instruments工具:Leaks,Allocation.
2. MLeakFinder工具。
卡顿检测:
1. 开发阶段可以用CADisplayLink,添加到runloop中.
2. 线上监测,除了用第三方SDK之外,可以使用 “在子线程添加observer监测主线程”的方式.
CPU使用率
CPU的使用也可以通过两种方式来查看,一种是在
调试
的时候Xcode会有展示,具体详细信息可以进入Instruments内查看,通过查看Instruments的time profile来定位并解决问题。另一种常见的方法是通过代码读取CPU使用率,然后显示在App的调试面板上,可以在Debug环境下显示信息,具体代码如下:
int result;
mib[0] = CTL_HW;
mib[1] = HW_CPU_FREQ;
length = sizeof(result);
if (sysctl(mib, 2, &result, &length, NULL, 0) < 0)
{
perror("getting cpu frequency");
}
printf("CPU Frequency = %u hz/n", result);
FPS监控
目前主要使用CADisplayLink来监控FPS,CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。我们在应用中创建一个新的 CADisplayLink 对象,把它添加到一个runloop中,并给它提供一个 target 和selector 在屏幕刷新的时候调用,需要注意的是添加到runloop的common mode里面,代码如下:
- (void)setupDisplayLink {
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTicks:)];
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)linkTicks:(CADisplayLink *)link
{
//执行次数
_scheduleTimes ++;
//当前时间戳
if(_timestamp == 0){
_timestamp = link.timestamp;
}
CFTimeInterval timePassed = link.timestamp - _timestamp;
if(timePassed >= 1.f)
//fps
CGFloat fps = _scheduleTimes/timePassed;
printf("fps:%.1f, timePassed:%f/n", fps, timePassed);
}
}
启动时间
点评App里面本身就包含了很多复杂的业务,比如外卖、团购、到综和
酒店
等,同时还引入了很多第三方SDK比如微信、QQ、
微博
等,在App初始化的时候,很多SDK及业务也开始初始化,这就会拖慢应用的启动时间。
App的启动时间t(App总启动时间) = t1(main()之前的加载时间) + t2(main()之后的加载时间)。
t2 = main方法执行之后到AppDelegate类中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法执行结束前这段时间,主要是构建第一个界面,并完成渲染展示。
- 针对t1的优化,优化主要有如下:
- 减少不必要的framework,因为动态链接比较耗时;
- 检查framework应当设为optional和required,如果该framework在当前App支持的所有iOS系统版本都存在,那么就设为required,否则就设为optional,因为optional会有些额外的检查;
- 合并或者删减一些OC类,这些我会在后续的静态检查中进行详解;
针对t2的时间优化,可以采用:
- 异步初始化部分操作,比如网络,数据读取;
- 采用延迟加载或者懒加载某些视图,图片等的初始化操作;
- 对与图片展示类的App,可以将解码的图片保存到本地,下次启动时直接加载解码后的图片;
- 对实现了+load()方法的类进行分析,尽量将load里的代码延后调用。
UI的主线程监测
我们都知道iOS的UI的操作一定是在主线程进行,该监测可以通过hook UIView的如下三个方法
-setNeedsLayout,
-setNeedsDisplay,
-setNeedsDisplayInRect
确保它们都是在主线程执行。子线程操作UI可能会引起什么问题,苹果说得并不清楚,但是在实际开发中,我们经常会遇到整个App的动画丢失,很大原因就是UI操作不是在主线程导致。
2 静态分析过程
静态分析在这里,我主要介绍两方面,一个是正常的code review机制,另外一个就是代码静态检查工具
code review
1.我们开发中首先都是在
测试
环境开发,开发时可以将测试环境的url写死到代码中,但是在提交代码的时候一定要将他改为线上环境的url,这个就可以通过
git
lab中的重点比较部分字符串,给提交者一个强力的提示;
2.其他常见Crash的重点检查,比如NSMu
tab
leString/NSMutableArray/NSMutableDictionary/NSMutableSet 等类下标越界判断保护,或者 append/insert/add nil对象的保护;
3.ARC下的release操作,UITableViewCell返回nil,以及前面介绍的常见的循环引用等。
代码静态检查
代码静态分析(Static Program Analysis)是指在不运行程序的条件下,由代码静态分析工具自动对程序进行分析的方法. iOS常见的静态扫描工具有Clang Static Analyzer、OCLint、Infer,这些主要是用来检查可能存在的问题,还有Deploymate用来检查api的兼容性。
Clang Static Analyzer
Clang Static Analyzer是一款静态代码扫描工具,专门用于针对C,C++和Objective-C的程序进行分析。已经被Xcode集成,可以直接使用Xcode进行静态代码扫描分析,Clang默认的
配置
主要是空指针检测,类型转换检测,空判断检测,内存泄漏检测这种等问题。如果需要更多的配置,可以使用开源的Clang项目,然后集成到自己的CI上。
热修复
SPatch 的原理就是:JS传递字符串给OC,OC通过 Runtime 接口调用和替换OC方法。
降级
用户使用App一段时间后,可能会遇到这样的情况:每次打开App时闪退,或者正常操作到某个界面时闪退,无法正常使用App。这样的用户体验十分糟糕,如果没有一个好的解决方案,很容易被用户
删除
App,导致用户量的流失。因为热更新基本不能使用,那就只能是App自身修复能力。目前常用的修复能力有:
- 启动Crash的监控及修复
1 在应用起来的时候,记录flag并保存本地,启动一个定时器,比如5秒钟内,如果没有发生Crash,则认为用户操作正常,清空本地flag。
2 下次启动,发现有flag,则表明上次启动Crash,如果flag数组越大,则说明Crash的次数越多,这样就需要对整个App进行降级处理,比如登出账号,清空
Document
s/Library/Caches
目录
下的文件。
- 具体业务下的Crash及修复
针对某些具体业务Crash场景,如果是上线的前端页面引起的,可以先对前端功能进行回滚,或者隐藏入口,等修复完毕后再上线,如果是客户端的某些异常,比如
数据库
升迁问题,主要是进行业务数据库修复,缓存文件的删除,账号退出等操作,尽量只修复此业务的相关的数据。
- 网络降级
比如点评App,本身有CIP(公司内部自己研发的)
长连接
,接入腾讯云的WNS长连接,
UDP
连接,HTTP
短连接
,如果CIP
服务器
发生问题,可以及时切换到WNS连接,或者降级到Http连接,保证网络连接的成功率。
线上监控
Crash监控
Crash是对用户来说是最糟糕的体验,Crash日志能够记录用户闪退的崩溃日志及堆栈,
进程
线程信息,版本号,系统版本号,系统机型等有用信息,收集的信息越详细,越能够帮助解决崩溃,所以各大App都有自己崩溃日志收集系统,或者也可以使用开源或者付费的第三方Crash收集平台。
端到端成功率监控
端到端监控是从客户端App发出请求时计时,到App收到数据数据的成功率,统计对象是:网络接口请求(包括H5页面加载)的成败和端到端延时情况。端到端监控SDK提供了监控上传接口,调用SDK提供的监控
API
可以将数据上报到监控服务器中。
用户行为日志
用户行为日志,主要记录用户在使用App过程中,点击元素的时间点,浏览时长,跳转流程等,然后基于此进行用户行为分析,大部分应用的推荐算法都是基于用户行为日志来统计的。某些情况下,Crash分析需要查询用户的行为日志,获取用户使用App的流程,帮助解决Crash等其他问题。
代码级日志
代码级别的日志,主要用来记录一个App的性能相关的数据,比如页面打开速度,内存使用率,CPU占用率,页面的帧率,网络流量,请求错误统计等,通过收集相关的上下文信息,优化App性能。