美文网首页内存
iOS APP性能检测&优化(一)

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

作者: ZJ_偶尔上路 | 来源:发表于2019-06-27 17:12 被阅读0次

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

    • 启动时间
    • 内存
    • 刷新帧率
    • 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 <mach/mach.h>
    #import <mach/task_info.h>
    
    - (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性能检测&优化(一)

        本文链接:https://www.haomeiwen.com/subject/jcnafctx.html