首页 > 其他分享 >iOS启动优化/耗电优化

iOS启动优化/耗电优化

时间:2023-02-25 14:06:41浏览次数:49  
标签:函数 app iOS 耗电 dyld main 优化 加载


一、启动优化

1.pre-main阶段

我们可以通过苹果提供了XCode内建的测量方法,

  • 1.点击项目名称
  • 2.​​Edit scheme...​
  • 3.左侧​​Run​
  • 4.中间顶部菜单​​Auguments​
  • 5.在​​Environment Variables​​​中添加一个环境变量​​DYLD_PRINT_STATISTICS​​,并设为 1

再次运行项目,会得到以下输出

iOS启动优化/耗电优化_初始化

主要分为3个加载阶段

  • 1.加载应用的可执行文件(app自身的所有.o文件集合)
  • 2.加载动态链接器​​dyld​​(dynamic loader一个专门用来加载动态链接库的库)
  • 3.​​dyld​​递归加载应用所有需要的动态链接库

优化:
Apple官方视频讲解 ​​​https://developer.apple.com/videos/play/wwdc2016/406/​

1.Load dylibs

iOS启动优化/耗电优化_iOS_02


一般iOS应用会加载100-400个dylibs,这些库都是系统的,并且Apple也做了很多的优化。

这一阶段主要就是分析应用以来的dylib(现在名为.tbd),找到其mach-o文件,然后验证其有效性,接着注册到内核,最后对dylib的每一个segment调用nmap()

2.Rebase/Bind

iOS启动优化/耗电优化_耗电优化_03

在dylib的加载过程中,系统为了安全考虑,引入了ASLR(Address Space Layout Randomization)技术和代码签名。由于ASLR的存在,镜像(Image,包括可执行文件、dylib和bundle)会在随机的地址上加载,和之前指针指向的地址(preferred_address)会有一个偏差(slide),dyld需要修正这个偏差,来指向正确的地址。

Rebase在前,Bind在后,Rebase做的是将镜像读入内存,修正镜像内部的指针,性能消耗主要在IO。Bind做的是查询符号表,设置指向镜像外部的指针,性能消耗主要在CPU计算。

我们在这一步可以做的优化有:

  • 1.减少ObjC类(class)、方法(selector)、分类(category)的数量
  • 2.减少C++虚函数的的数量(创建虚函数表有开销)
  • 3.使用Swift structs(内部做了优化,符号数量更少)
3.ObjC Setup

iOS启动优化/耗电优化_加载_04


大部分ObjC初始化工作已经在Rebase/Bind阶段做完了,这一步dyld会注册所有声明过的ObjC类,将分类插入到类的方法列表里,再检查每个selector的唯一性。

在这一步倒没什么优化可做的,Rebase/Bind阶段优化好了,这一步的耗时也会减少。

4.Initializers

iOS启动优化/耗电优化_耗电优化_05

到了这一阶段,dyld开始运行程序的初始化函数,调用每个Objc类和分类的+load方法,调用C/C++ 中的构造器函数(用attribute((constructor))修饰的函数),和创建非基本类型的C++静态全局变量(通常是类或结构体)。Initializers阶段执行完后,dyld开始调用main()函数。

Objc的load函数和C++的静态构造函数采用由底向上的方式执行,来保证每个执行的方法,都可以找到所依赖的动态库。例:

我们在这一步可以做的优化有:

  • 1.少在类的+load方法里做事情,尽量把这些事情推迟到+initiailize
  • 2.减少构造器函数的个数,在构造器函数里少做些事情
  • 3.减少C++静态全局变量的个数

2.main阶段

主要分为4个加载阶段

  • 1.​​dyld​​调用main()函数
  • 2.调用​​UIApplicationMain​​函数
  • 3.调用​​applicationDidFinishLaunching​​方法
  • 4.调用​​didFinishLaunchingWithOptions​​方法

那么这些是我们可以通过代码来优化的地方,比如在一开始,不要初始化那么多的SDK或者功能,是否考虑一些初始化可以在子线程操作等

我们可以通过main阶段耗时加载多久
1.先在main函数这里设置当前时间

CFAbsoluteTime StartTime;
int main(int argc, char * argv[]) {
StartTime = CFAbsoluteTimeGetCurrent();
......

2.再在AppDelegate.m文件中用extern声明全局变量StartTime

extern CFAbsoluteTime StartTime;

3.最后在didFinishLaunchingWithOptions里,再获取一下当前时间,与StartTime的差值即是main()阶段运行耗时。

double launchTime = (CFAbsoluteTimeGetCurrent() - StartTime);
NSLog(@"耗时 launchTime = %lf 秒", launchTime);






二、耗电优化

主要集中在

  • 1.网络 ​​Network​
  • 2.定位
  • 3.蓝牙
  • 4.app前后台
  • 5.​​CPU​​计算
  • 6.​​GPU​​渲染

1.定位功能

  • app推到后台时,非导航功能之外,可以暂停定位功能,比如:把​​pauseLocationUpdatesAutomatically = YES;​
  • 设置定位的精度越高,定位硬件模块功耗越大,如果不是要求特别精准的功能,可以把定位精度降低
  • 按需使用定位,不用的时候关闭它

2.网络请求

  • app推到后台时,尽量减少网络请求,不是必要的请求,可以等用户切换到前台时再去请求
  • app退到后台时,大部分的时候,刷新UI的操作是不必要的

其他

  • 刷新UITableView或者UICollectionView的时候,尽量做到刷新一行,或者刷新一个section
  • 像对UIView的圆角、阴影等效果能用图片图标做到的,一律不用代码写
  • 网络请求的数据如果需要的话,尽量做本地缓存
  • 蓝牙按需使用,不用的时候关闭它
  • 定时器Timer的使用频次减少
  • 大文件I/O操作时,可以用​​dispatch_io​

比如:滴滴这种app,很多时候希望在1%的电量时,还能打个车,这个时候,我们要尽量把除了发布打车订单的请求保留,其他的数据请求应该暂时禁用。


标签:函数,app,iOS,耗电,dyld,main,优化,加载
From: https://blog.51cto.com/u_14062833/6085419

相关文章