大师课笔记,持续更新~

一、 崩溃相关

1、 收集Nativity异常,可采用 Breakpad 框架
资料来源:https://mp.weixin.qq.com/s/g-WzYF3wWAljok1XjPoo7w?
它的原理为:
①:当应用崩溃时,Linux会抛出信号量(信号量是一种进程间的通信方式)
②:内核会自动接收到信号量,并且通知进场进入内核态。
③:当进程从内核态切换到用户态或者在内核态从睡眠状态被唤醒时,会检查信号量
④:当检查到信号之后,会把内核栈的数据拷贝到用户栈上,并且在用户态下执行处理函数。
⑤:所以,捕获Nativity异常需要注册信号量的处理函数,并且处理对应的异常。信号量有相应的对应表,可以进行case处理。
具体函数如下:
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
act 是处理的函数指针 长这样:
static void signal_handler(constint code, siginfo_t *const si,
void *const sc)
⑥:如何获得堆栈信息?
在第五点中:signal_handler 的第三个参数,是Cpu相关的上下文,有当前崩溃的pc值(pc值又是什么?) pc 值可以得到栈stack的调用顺序。
2、 异常崩溃的注意事项:在收集异常时,最好是clone一个进程(java中如何clone进程?)
3、 如何解决系统的异常?可通过分析系统的源码,代理解决问题。张绍文举了一个处理Toast时窗口关闭的系统异常,只在7.0上出现。通过代理Toast中的mTN变量来解决。(问题来,mTN是一个final并且私有的变量,通过代理?这里可能要用到java的反射)

二、 内存相关

内存第一讲:
1、 内存和类型有很大的关系,大致分为:LPDDR3、LPDDR4、LPDDR4X。主要的差别在带宽和工作电压。
2、 内存不足会产生oom异常和频繁GC造成卡顿,在Dalvik虚拟机上更为明显,art虚拟机做了内存的优化。(目前还没有弄清楚是什么优化)
3、 bitmap的内存优化:在3.0之前。bitmap的像素数据是放在了Native,但是像素数据无法和对象一起回收,依赖于finalize函数的回调(finalize 是java对象被回收时调用)。在3.0 到 7.0 像素数据和Bitmap对象一起放到java堆,但是因为系统限制了应用的内存大小,即使物理内存不断的增大,但是应用的内存都只是512M,所以这种做法容易引起频繁的GC,导致卡顿。在Android 8.0之后 Bitmap 采用了NativeAllocationRegistry与native绑定。(NativeAllocationRegistry 实现原理待分析)

内存第二讲:
1、 设备分级
2、 根据剩余内存的大小,释放对应的内存(OnTrimMemory回调)
3、 开辟内存时,做到接口聚拢,方便监控
4、 Bitmap优化,图片的尺寸问题
5、 重复图片的用一张(如何判断图片是否重复?可随机取像素点,也可计算图片的hash值,一般放在后端做)

三、 卡顿相关:

卡顿第一讲:
Android的分析工具:
①、Traceview可以分析出整个过程方法的执行时间,但是缺点就是这个工具本身会带来很大的性能开销,会放大方法的执行时间,并且不是等比例放大。
②、Systrace相当于在系统的各个关键位置增加了一些性能探针(怎么增加的目前还不知道)。开启方式和关闭方式:Trace.beginSection和Trace.endSection。
Systrace可通过编译时给每个函数插桩(如何插桩?)的方式显示监控所有方法。
这两种工具的差别就是Traceview很卡,因为收集了所有的调用过程。而Systance相对而言好很多。还有在高手课里,说这是两个流派,我还没有搞懂两个流派有什么区别
卡顿第二讲:
如何线上监控?
一、 可以设置Looper中的mLogging,Handle机制中会去调用这个接口。此接口的不足就是,Looper在调用mLogging时,会去凭借字符串,导致性能的下降。
二、 可以在固定的时间间隔里循环发送消息,判断当前队列是否阻塞。不足之处是得到的堆栈可能不准确。但是问题不大,可以通过日志去重分析发生次数定位到真正的问题点。
线上分析处每个方法的执行时间?通过编译时插桩(如何实现编译时插桩?)。这种方式得到的就只是自己的写的方法,无法和TraceView得到系统方法的调用。

Facebook 的 Profilo 实现了快速获取 Java 堆栈,其实它参考的是 JVM 的 AsyncGetCallTrace 思路,然后适配 Android Runtime 的实现。

四、 启动优化相关

启动过程分为四个:T1 预览窗口显示,T2闪屏显示、T3主页显示、T4界面可操作。启动优化应该是从启动到界面可操作
优化工具:通过systrace + 函数插桩 的方式 (如何实现编译时插桩?)
优化方式:
①:闪屏优化。第一种做法是可以通过设置Theme,可以快速看到预览,但是有一个问题时,并没有解决真正问题,在一些低端机里,会让客户觉得是App卡了,而不是系统卡了。
第二种做法是,把闪屏页面和主页面放到一个Activity里,这样可以节省启动一个Activity的时间。但是会造成代码耦合,逻辑复杂。
②:业务梳理。减少模块的启动,不必要的模块用懒加载代替,在低端机中,要学会砍掉一些功能,低端机用低配版,快速启动。在文稿里有一句话,没有看懂:懒加载要防止集中化,否则容易出现首页显示后用户无法操作的情形。在一些必须要模块,要评估是否可以用异步预加载,在主页面用到的时候,采用监听回调的方式。
③:线程优化。当走到多线程去初始化数据时,就要考虑到线程优化的问题了。
1、 多线程初始化,不是越多线程越好,要让每个线程都在跑,而不是频繁去抢占CPU时间片。所以需要统一的线程池,根据机器性能解决线程数量的大小
2、 多线程的同步问题。模板的初始化过程中,有相互的依赖关系,会导致一些线程在等待。解决的办法是建立一个有向无环图,解决依赖问题。
④:GC优化。1、要避免大对象的创建。2、内存能复用就复用。
⑤:尽量避免系统调用。系统调用普遍涉及到进程间通信,比较耗时。更不要去创建新进程。


版权声明:本文为s2311307原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。