iOS APP性能检测&优化(一)

性能优化,都要优化什么?

  • 启动时间
  • 内存
  • 刷新帧率
  • UI阻塞次数,不可操作时长,主线程阻塞超过400毫秒次数
  • CPU使用率
  • GPU使用率
  • 网络请求时间,流量消耗
  • 耗电功率

如何去监测这些性能指标。

  • Xcode自带的Instrument Instrument 用户指南(中文版)
    Instrument 性能检测图谱:

    Instrument 性能检测图谱.jpeg

  • 使用第三方SDK :Bugly、OneAPM、听云、Firebase Analytics

  • 自行开发检测代码

启动时间

1.通过Instrument的Time Profiler,找到包含-[UIApplication _reportAppLaunchFinished]的最后一帧,可计算出启动时间。

2.自行添加代码计算
t1
系统dylib和自身app可执行文件(app中所有.o文件的集合)的加载
Launch页

t2
main()
UIApplicationMain()
willFinishLaunchingWithOptions()
didFinishLaunchingWithOptions()

t3
loadView()
viewDidLoad()
applicationDidBecomeActive()

启动时间 t = t1 + t2;
app从启动到打开第一个页面的时间 t = t1 + t2 + t3;

t1:在Xcode的Edit scheme中增加
DYLD_PRINT_STATISTICS这个环境变量,控制台就会打印这个时间。


launch time.png

t2、t3都可以通过埋点的方式添加获取时间的代码即可。

内存

目前在开发的阶段只会注意内存泄露和内存异常两种情况,具体的内存分配、僵尸对象等可能会在开发结束后进行检测。

内存泄露除了使用instrument,还有:

  • 手动添加代码:
- (void)delloc {
      NSLog(@"------------->--->%@被释放了",[self class]);
}

这个只是说明某个类释放情况,并不能定位到具体代码,需要在类内部进行排查。

  • 第三方工具MLeaksFinder,优点:
    1.这个库不需要入侵项目代码,直接pod导入一下库就
    2.不用像instruments那么麻烦,还需要自己来仔细观察
    3.库只在debug状态运行,完全不影响app打包大小

内存异常就只是观察Xcode里面的内存显示或者埋点插入内存计算的方法,代码如下:

#import 
#import 

- (unsigned long)memoryUsage
{
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);  
    if (kr != KERN_SUCCESS) {    
        return -1;
    }
    unsigned long memorySize = info.resident_size >> 10;//10-KB   20-MB   

    return memorySize;
//返回的数值单位是KB,如果想要MB的话把10改为20。
}

刷新帧率
刷新帧率利用CADisplayLink做一个小工具进行检测,查看认识并使用CADisplayLink。

UI阻塞次数,不可操作时长,主线程阻塞超过400毫秒次数

美团移动端性能监控方案Hertz
在实践中采用的是检测主线程每次执行消息循环的时间,当这一时间大于阈值时,就记为发生一次卡顿。

卡顿检测.png

开辟一个子线程,然后实时计算 kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting 两个状态区域之间的耗时是否超过某个阀值,来断定主线程的卡顿情况。这个还是比较准确的数据。
但是由于主线程的RunLoop在闲置时基本处于Before Waiting状态,这就导致了即便没有发生任何卡顿,这种检测方式也总能认定主线程处在卡顿状态。

CPU使用率
CPU使用率只需观察Xcode里面的数据或者埋点插入CPU使用率计算的方法,代码如下:

- (float)cpu_usage
{
    kern_return_t            kr = { 0 };
    task_info_data_t        tinfo = { 0 };
    mach_msg_type_number_t    task_info_count = TASK_INFO_MAX;

    kr = task_info( mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count ); 
    if ( KERN_SUCCESS != kr )   
        return 0.0f;

    task_basic_info_t        basic_info = { 0 };
    thread_array_t            thread_list = { 0 };
    mach_msg_type_number_t    thread_count = { 0 };

    thread_info_data_t        thinfo = { 0 };
    thread_basic_info_t        basic_info_th = { 0 };

    basic_info = (task_basic_info_t)tinfo;    // get threads in the task
    kr = task_threads( mach_task_self(), &thread_list, &thread_count ); 
    if ( KERN_SUCCESS != kr )   
        return 0.0f;  
    long    tot_sec = 0;  
    long    tot_usec = 0;  
    float    tot_cpu = 0;  
    for ( int i = 0; i < thread_count; i++ )
    {
        mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX;

        kr = thread_info( thread_list[i], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count );   
         if ( KERN_SUCCESS != kr )       
              return 0.0f;

        basic_info_th = (thread_basic_info_t)thinfo;   
         if ( 0 == (basic_info_th->flags & TH_FLAGS_IDLE) )
        {
            tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds;
            tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE;
        }
    }

    kr = vm_deallocate( mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t) );  
           if ( KERN_SUCCESS != kr )    
               return 0.0f;   
            return tot_cpu * 100.; // CPU 占用百分比}

具体使用可以使用instrument查看。

GPU使用率
iOS 设备跟踪 GPU 使用率
GPUUtilization GPU使用率检测Demo

网络请求时间,流量消耗
该部分在AFNetworking研究之后再做补充。

链接文章:
iOS APP性能检测&优化(二)

你可能感兴趣的:(iOS APP性能检测&优化(一))