前言

在项目中,直接面向用户的客户端往往是一个项意图门面。因而,在项目开发建造的过程中,为了交给用户体验较佳的客户端App,保证产品交给质量。往往需求咱们开发者重视客户端软件的功用指标问题。因而,咱们要对运用的功用优化专题有所研究!!
咱们一般重视的功用指标有:

  • 页面卡顿
  • 耗电、发热
  • 网络优化
  • 运用发动
  • 安装包减肥

咱们在开发建造项目过程中,可以粗略划分为几个阶段:开发阶段测验阶段维护阶段:

  • 开发阶段,咱们要把握功用调试功用监测的手法,从而保证,在当前安稳版别的客户端软件,有一个比较合理的功用保证;
  • 测验阶段,测验团队等若干搭档往往会给咱们提出一些用户体验上的反馈和主张,因而,咱们需求把握功用调试的手法,从而改造出比较契合团队要求的产品;
  • 在上线维护阶段,针对现已上线的运用,咱们的开发团队要有线上功用监控的能力,从而及时搜集不满足功用指标要求的事务交互场景和过程,捕获具体问题进行剖析,从而以此为依据作为有效迭代优化咱们客户端的有力助力。

为此,咱们本次将会用几篇文章,环绕一些常见的功用指标,去重视 怎么调试、怎么监测、怎么改善处理问题:

  • Instruments
    • 01-iOS功用优化|功用调试东西Instruments简略介绍
    • 02-iOS功用优化|功用调试东西Instruments-CoreAnimation运用
    • 03-iOS功用优化|功用调试东西Instruments-Leaks东西运用
    • 04-iOS功用优化|功用调试东西Instruments-Allocations东西运用
  • 其它功用指标的重视
    • 05-iOS功用优化|常见的几个功用指标关键:页面卡顿、离屏烘托、耗电优化、App发动优化、安装包减肥
    • 06-iOS功用优化|功用指标监测

一、概述

本文首要是针对 维护阶段 这两个线上场景,环绕常见的几个功用指标关键:页面卡顿离屏烘托耗电优化内存走漏App发动优化,展开来陈说怎么利用代码插件渠道东西进行功用指标监测的。关于相关的同一主题的其它关键,待来日按需逐个弥补完善。

二、卡顿的检测

平时所说的“卡顿”首要是由于在主线程执行了比较耗时的操作

1.FPS监控

FPS的监控,参照YYKit中的YYFPSLabel,首要是经过CADisplayLink完成。借助link的时刻差,来核算一次改写改写所需的时刻,然后经过改写次数 / 时刻差得到改写频次,并判别是否其范围,经过显示不同的文字颜色来表明卡顿严峻程度。代码完成如下

class HPFPSLabel: UILabel {
    fileprivate var link: CADisplayLink = {
        let link = CADisplayLink.init()
        return link
    }()
    fileprivate var count: Int = 0
    fileprivate var lastTime: TimeInterval = 0.0
    fileprivate var fpsColor: UIColor = {
        return UIColor.green
    }()
    fileprivate var fps: Double = 0.0
    override init(frame: CGRect) {
        var f = frame
        if f.size == CGSize.zero {
            f.size = CGSize(width: 80.0, height: 22.0)
        }
        super.init(frame: f)
        self.textColor = UIColor.white
        self.textAlignment = .center
        self.font = UIFont.init(name: "Menlo", size: 12)
        self.backgroundColor = UIColor.lightGray
        //经过虚拟类
        link = CADisplayLink.init(target: CJLWeakProxy(target:self), selector: #selector(tick(_:)))
        link.add(to: RunLoop.current, forMode: RunLoop.Mode.common)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    deinit {
        link.invalidate()
    }
    @objc func tick(_ link: CADisplayLink){
        guard lastTime != 0 else {
            lastTime = link.timestamp
            return
        }
        count += 1
        //时刻差
        let detla = link.timestamp - lastTime
        guard detla >= 1.0 else {
            return
        }
        lastTime = link.timestamp
        //改写次数 / 时刻差 = 改写频次
        fps = Double(count) / detla
        let fpsText = "(String.init(format: "%.2f", fps)) FPS"
        count = 0
        let attrMStr = NSMutableAttributedString(attributedString: NSAttributedString(string: fpsText))
        if fps > 55.0 {
            //流畅
            fpsColor = UIColor.green
        }else if (fps >= 50.0 && fps <= 55.0){
            //一般
            fpsColor = UIColor.yellow
        }else{
            //卡顿
            fpsColor = UIColor.red
        }
        attrMStr.setAttributes([NSAttributedString.Key.foregroundColor: fpsColor], range: NSMakeRange(0, attrMStr.length - 3))
        attrMStr.setAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], range: NSMakeRange(attrMStr.length - 3, 3))
        DispatchQueue.main.async {
            self.attributedText = attrMStr
        }
    }
} 

2.主线程卡顿监控

咱们可以增加Observer到主线程RunLoop中,经过监听RunLoop状况切换的耗时,以到达监控卡顿的意图

完成思路:

在整个运行循环中,需求监听的首要就是RunLoop结束休眠到处理Source0的这段时刻,如果时刻过长,就证明有耗时操作

检测主线程每次执行消息循环的时刻,当这个时刻大于规定的阈值时,就记为发生了一次卡顿。这个也是微信卡顿三方matrix的原理

以下是一个简易版RunLoop监控的完成

class HPBlockMonitor: NSObject {
    static let share = LLBlockMonitor.init()
    fileprivate var semaphore: DispatchSemaphore!
    fileprivate var timeoutCount: Int!
    fileprivate var activity: CFRunLoopActivity!
    private override init() {
        super.init()
    }
    public func start(){
        //监控两个状况
        registerObserver()
        //发动监控
        startMonitor()
    }
}
fileprivate extension LLBlockMonitor{
    func registerObserver(){
        let controllerPointer = Unmanaged<LLBlockMonitor>.passUnretained(self).toOpaque()
        var context: CFRunLoopObserverContext = CFRunLoopObserverContext(version: 0, info: controllerPointer, retain: nil, release: nil, copyDescription: nil)
        let observer: CFRunLoopObserver = CFRunLoopObserverCreate(nil, CFRunLoopActivity.allActivities.rawValue, true, 0, { (observer, activity, info) in
            guard info != nil else{
                return
            }
            let monitor: LLBlockMonitor = Unmanaged<LLBlockMonitor>.fromOpaque(info!).takeUnretainedValue()
            monitor.activity = activity
            let sem: DispatchSemaphore = monitor.semaphore
            sem.signal()
        }, &context)
        CFRunLoopAddObserver(CFRunLoopGetMain(), observer, CFRunLoopMode.commonModes)
    }
    func  startMonitor(){
        //创立信号
        semaphore = DispatchSemaphore(value: 0)
        //在子线程监控时长
        DispatchQueue.global().async {
            while(true){
                // 超时时刻是 1 秒,没有等到信号量,st 就不等于 0, RunLoop 所有的任务
                let st = self.semaphore.wait(timeout: DispatchTime.now()+1.0)
                if st != DispatchTimeoutResult.success {
                    //监听两种状况kCFRunLoopBeforeSources 、kCFRunLoopAfterWaiting,
                    if self.activity == CFRunLoopActivity.beforeSources || self.activity == CFRunLoopActivity.afterWaiting {
                        self.timeoutCount += 1
                        if self.timeoutCount < 2 {
                            print("timeOutCount = (self.timeoutCount)")
                            continue
                        }
                        // 一秒左右的衡量标准 很大可能性接连来 避免大规模打印!
                        print("检测到超越两次接连卡顿")
                    }
                }
                self.timeoutCount = 0
            }
        }
    }
} 

运用时,直接调用即可

HPBlockMonitor.share.start()

三、运用第三方库

咱们开发过程中,也可以运用一些不错的第三方库来做功用指标的监测。比方:腾讯的matrix、滴滴DoraemonKit。都是很不错的结构

1.DoraaemonKit简略介绍

DoraaemonKit支撑以下多种功用指标的监测:

  1. 【帧率】 App 帧率信息供给波形图检查功用,让帧率监控的趋势愈加显着;
  2. 【CPU】 App CPU 运用率信息供给波形图检查功用,让 CPU 监控的趋势愈加形象;
  3. 【内存】 App 内存运用量信息供给波形图检查功用,让内存监控的趋势愈加明显;
  4. 【流量监控】 拦截 App 内部流量信息,供给波形图展现、流量概要展现、流量列表展现、流量筛选、流量概况,对流量信息统一拦截,成为咱们 App 中自带的 “Charles”;
  5. 【卡顿】 锁定 App 出现卡顿的时刻,打印出对应的代码调用堆栈
  6. 【大图检测】 经过流量监测,找出所有的大小超标的图片,避免下载大图形成的流量浪费和烘托大图带来的CPU消耗。
  7. 【发动耗时】 无侵入的计算出App发动过程的一共耗时;
  8. 【UI层级检查】 检查出每一个页面中层级最深的元素;
  9. 【函数耗时】 从函数等级剖析app功用瓶颈;
  10. 【Load】 找出所有的Load办法,并给出耗时剖析;(iOS独有)
  11. 【内存泄漏】 找出App中所有的内存泄漏的问题。

2.DoraaemonKit支撑多个渠道

一套结构可以支撑一个项目组的多个渠道,这是一件十分符合团队管理者心意的事情。由于这保证了整个团队输出的质量!!!

06-iOS 性能优化|性能指标监测

3.DoraaemonKit底层完成

DoraaemonKit的作者真的很有心,还和广阔开发者们共享了其底层完成的代码

总结

本文 简略介绍了 项目功用调试东西Instruments的根本运用,目前只对Allocations调试这一块 做了简略介绍 。
接下来会用几篇文章,环绕几个常见的功用问题,展开对功用调试东西Instrument的 其它模块的运用介绍:

  • iOS 研制帮手 DoKit 技能完成(一)
  • iOS 研制帮手 DoKit 技能完成(二)
  • DoKit支撑iOS本地crash检查功用
  • 开源组件 DoKit 之 Android 版别技能完成(一)
  • 开源组件 DoKit 之 Android 版别技能完成(二)
  • DoKit支撑Activity发动耗时计算方案
  • DoKit 微信小程序SDK对外发布
  • 滴滴DoKit2.0 – 泛前端开发者的百宝箱
  • 滴滴正式发布开源客户端研制帮手 DoKit 3.0,新特性解读
  • 滴滴DoKit Android中心原理揭秘之函数耗时
  • 滴滴DoKit Android中心原理揭秘之AOP字节码完成

相关系列文章

Instruments

  • 01-iOS功用优化|功用调试东西Instruments简略介绍
  • 02-iOS功用优化|功用调试东西Instruments-CoreAnimation运用
  • 03-iOS功用优化|功用调试东西Instruments-Leaks东西运用
  • 04-iOS功用优化|功用调试东西Instruments-Allocations东西运用 其它功用指标的重视
  • 05-iOS功用优化|常见的几个功用指标关键:页面卡顿、离屏烘托、耗电优化、App发动优化、安装包减肥
  • 06-iOS功用优化|功用指标监测