Need help with Performance?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

liuyangbajin
133 Stars 20 Forks 6 Commits 2 Opened issues

Description

一线大厂中的大型App全套性能优化实战方案,讲解你们所不知道的优化内容,包含启动优化,内存优化,网络优化,容灾方案等等,每周会定时更新,欢迎关注博客

Services available

!
?

Need anything else?

Contributors list

No Data

1.前言

最近感觉真的很懒惰,答应几个小伙伴的更新,也迟迟没更,今天给补上。这一章主要是对前4章学习的总结

一线大厂资深APP性能优化系列-卡顿定位(一)

一线大厂资深APP性能优化系列-异步优化与拓扑排序(二)

一线大厂大型APP性能优化系列-自定义启动器(三)

一线大厂大型APP性能优化系列-更优雅的延迟方案(四)

这四章其实也是启动优化这一个大章节的内容,看完这4个,至少启动优化这个地方就已经很OK了。 当然接下来我们会进入 第二大章节的内容学习了,第二大章节,预计有5个小章节组成,是全套介绍在一个真实项目中的如何进行内存优化 希望大家能提前先了解下关于内存优化这方面的知识。

当然了,之前也吐槽过,学习一定要扎实,很多人对于内存优化这方面的内容的理解就是:LeakCanary的使用及原理,但是检测出来如何优化?如何避免这些问题,这就是经验了


2.卡顿定位总结

这是我们第一大章中的第一小章,具体看

一线大厂资深APP性能优化系列-卡顿定位(一)

在这一章我们主要讲的就是如何获取方法耗时,工欲善其事,必先利其器,这也是日常我们进行大项目优化的第一步,先分析一下这个大项目的耗时情况,有很多同学反映说是进行老项目维护升级,卡顿无从下手,所以分析卡顿的耗时时间就是进行项目优化的第一步。

1.常规方式

直接在每个方法上下各加入一行代码,然后打印,如:

public void func(){
    long startTime = System.currentTimeMillis();
     xxxx
    Log.d("lybj", "func()方法耗时:"+ (System.currentTimeMillis() - startTime));
}

简单是简单,但是记住我们做性能检测的,是不能写这种入侵性很强的代码,很有可能本来很稳定的系统,因为你的性能检测的代码,变成了不稳定,这是不被允许的。所以废弃!

2.Aop方式

这种方式尼,可以使得我们的性能检测代码与逻辑代码相分离

@Aspect
public class PerformanceAop {

@Around("call(* com.bj.performance.MyApplication.**(..))")
public void getTime(ProceedingJoinPoint joinPoint){

    long startTime = System.currentTimeMillis();
    String methodName = joinPoint.getSignature().getName();
    try {
        joinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    Log.d("lybj", methodName + "方法耗时:"+ (System.currentTimeMillis() - startTime));
}

}

缺点: 如果项目比较庞大,上百个方法,总不能全部打点,然后一个一个的分析到底是哪个地方运行时间过长吧,所以我们需要一个比较直观的工具,一眼就能看到具体哪个方法运行时间过长。

3.wall time 与 cpu time

在traceView里面的时间模式有两种:

wall time 就是执行这段代码的时间,但是如果该线程被卡住了,等待的时间也是被算在内的。

cpu time(Thread Time) 则是CPU具体花在这个线程上的时间,它的时间也一定小于wall time的时间,

所以如果发现wall time 时间很长,cpu time时间很短,那么就说明了一件事,你需要开异步线程了,因为耗时的主要原因都是,CPU在闲置,而你的线程在等待。


3.异步优化总结

启动优化的开端,对application里面初始化的第三方依赖进行优化,这个涉及到两章内容,如下:

一线大厂资深APP性能优化系列-异步优化与拓扑排序(二)

一线大厂大型APP性能优化系列-自定义启动器(三)

1.常规方式

可以使用线程池或者开启线程去实现,目的很简单,为了帮主线程分担压力。

缺点:1.如果两个异步之间执行的内容有着依赖关系,则不好处理

比如我们要初始化极光推送,还要获取设备ID,假如这两个都是耗时方法,均需要在子线程中进行初始化,但是必须得先获取设备ID,再初始化极光推送,两者之间存在依赖关系,则不是很好处理了,具体查看第二章节内容。

缺点:2.如果其中一个异步处理,需要先执行完毕自己,主线程才能继续往下执行,那么常规方式也不好处理。

缺点:3.如果上面两个你通过同步锁机制都处理了,那么恭喜你,你的代码可读性肯定不高!

2.启动器原理

还记得吗,咱们一起实现了个启动器,原理很简单,具体看第三章,这里只是简述:

task

首先是将我们的耗时操作均封装成一个task,它有4个方法1个属性

属性1 :CountDownLatch,该task有几把锁尼,取决于它的依赖的task集合数。
方法1 :dependsOn()返回它所依赖的task集合
方法2 :waitToSatisfy()开启锁
方法3 :satisfy()执行完一个依赖,减少一把锁
方法4 :needWait() 是否需要主线程等你执行完再执行

启动器(TaskDispatcher)

启动器主要是用来分发task的

属性1:mCountDownLatch 锁,不同于task里的锁,这个锁是锁主线程的,当主线程调用它时,它会锁定,锁的数量取决于等待集合(mNeedWaitTasks)的数量

方法1:addTask: 将task添加至集合中,并以需要依赖的对象为key,集合为value创建一个Map,这个Map是做什么的尼?主要啊,当一个task运行完毕,就可以循环这个Map找到这个运行完毕的task,获取到需要依赖它的对象集合,然后让每一个对象,均减少一把锁。然后调用这个task的needWait()方法,看看是否需要主线程等待它,如果需要,加入等待集合(mNeedWaitTasks)中

方法2:startTask:分发task,首先是根据有向无环图的拓扑排序,将task集合重新排序,比如,我们传入的任务是A,B,C但是尼,如果A依赖于B,那么就需要先初始化B,同时处理C,然后再处理A。返回就是B、C、A。设置主线程的锁,锁的数量就是等待集合(mNeedWaitTasks)的数量,保证一些要切换页面之前必须要执行完的task均执行完。然后根据所要求的线程进行分发处理。

执行器(DispatchRunnable)

执行器主要就是为了执行task的,它继承了Runnable

方法1:run(): 启动task里面的锁,还记得不,它的锁的数量取决于它所依赖的对象数,目的就是先执行完它的依赖。然后尼,执行task里面的run方法,这个是个空方法,用于执行我们的耗时任务,然后执行启动器的satisfyChildren方法,还记得吗,就是用来循环之前存的Map找到这个运行完毕的task,获取到需要依赖它的对象集合,然后让每一个对象,均减少一把锁。

是不是很简单?不理解的就去研究第三章内容,熟读并背诵


4.更加优雅的异步加载

涉及到一章内容,如下:

一线大厂大型APP性能优化系列-更优雅的延迟方案(四)

1.常规方式

可以通过Handler().sendMessageDelayed() 达到延迟加载

但是项目中是不建议这样用的,因为会抢占CPU,性能会进行耗损,比如一个页面的一些第三方服务进行初始化操作,虽然说是可以延迟一段时间再去初始化,但是如果该页面有任务一直在执行,比如有个定时器或者轮询请求接口等,那么延时的时间到了,依然是要抢占CPU来执行我们的第三方服务的初始化操作。所以不能直接这么用

2.IldeHandler

这个是没问题的,可以在CPU空闲时间进行处理耗时操作,但是如果加入的任务存在着先后执行顺序等,就无法单纯的使用它了,因为它是无序的,加入的任务是谁有空执行谁

3.异步启动器

具体看第四章节内容,这里只是简介

IldeTaskDispatcher

原理很简单,有一个方法addTask()作用就是把task添加到集合里面,然后封装一个IldeHandler,遍历这个集合,取得task后,交给DispatchRunnable去执行它,DispatchRunnable就是我们第三章节时封装的。


5.源码

好了,这里有大家最期待的源码

点击下载 记得点个星!


6.END

愉快的假期生活完事了,公司要求复工了,真是一个悲伤的故事。

经过了一个月,总算是把第一大章节启动优化的内容更新完了,基本也就这些内容,在网上查了查虽然还有很多,比如预加载字节码文件等,但是尼,其实感觉没必要,一个软件快了0.1秒其实是作用不大的,还有的说是锁定CPU的频率,但是你就无法保证节约电量的作用,当然还有些适配方案,但是经过验证,要么没什么效果,要么有些华而不实。基本上掌握了上述的4个章节,启动优化就够了,即便是大厂优化到这个程度也是可以了。

接下来的几周会给大家更新第二大章节的内容,涉及的是在实战项目中关于内存的优化方案。大家记得要复习一下!

最后:欢迎大家 点赞+关注,你们的支持是我继续更新完下面 16-17 章内容的动力!

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.