1.BlockCanary卡顿监控原理

1.BlockCanary卡顿监控原理

内存监控也能够帮助我们定位到卡顿问题,卡顿的原因有哪些?掉帧 主线程阻塞  ui繁重慢了只是照成卡顿的原因之一 ,并不是只有ui的绘制才会导致卡顿问题,我们的 内存抖动也会照成卡顿 并发锁的竞争也会照成卡顿问题 

 频繁的io操作也会照成卡顿现象

Shared Preference的使用不当也会导致程序出现卡顿 原理是什么?

卡顿监控:

问原理源码 

 

 

 

 

 我们程序启动就是靠我们的main方法启动的

 ApplicationThread 继承stub 

aidl 会生成两个类一个是stub 一个是 Proxy Proxy代表了stub的一个代理

ams 持有了应用进程的ApplicationThread 他的代理类Proxy,然后ams使用Proxy去执行我们的stub方法,其实是通过代理类 执行我们的stub方法 也就执行到ApplicationThread 说白了,ams回去执行ApplicationThread里面的方法,那么其中有一个方法叫scheduletaunchactivity SChedueAUICTwActdVity 会调用sendmessage 其实就是发了一个Handler Message 消息 去把我们的activity启动起来,执行activity的oncreate方法 不要求记这个流程 要把这个流程表背下来,只需要知道Android当中的应用里面的 无论是activity的声明周期,还是fragment的生命周期 还是Application的启动,他最终都是通过发一个Handler消息 然后在Handler里面去把我们的这些生命周期的方法去调用起来  写的这些代码都是通过Handler消息,最终都是我们的一个一个的message执行起来的

api 30里设有launch activity msg了 


 

android的api28之后发生了重构 方法名字变了,但最终仍然使用Handler的消息 驱动起来的 代码都是在message处理的时候, 处理message的时候一个一个执行起来的  代码都是通过Handler驱动起来的,这个Handler就是在ActiwityThresd.java 有个H 这个H就是我们的Handler

 

Handler的执行消息是怎么执行的?Handler跟他相关的有Message Messagequeue 

Messagequeue 就是队列  我们一个一个的Message 都在里面 一个一个排队执行的,然后要通过Looper去在Messagequeue当中 去把一个一个消息取出来,然后交给dispatchMessag进行一个分发 最终执行我们的handleMesSag

Looper可以看作一个消息的传递

 Looper方法里面,去从MessageQueue去取消息 他是一个死循环

 把这个MessageQueue取出Message,然后把这个Message进行dispatchMessage去进行执行

 在执行这个消息之前比如这个消息封装的是activity的oncreate方法 在执行oncreate之前,他会去做 他把Message从MessageQueue取出来之后,他要去调用一个Printer的println的方法 会传一个Dispatching to 这样的字符串 给到我们的Printer  在真正执行消息之后 他就又会使用这个logg发一个Finished to  我们可以设置一个自己的Printer 给到我们的looper 给到我们的MessageQueue 然后我们就可以在我们自己的
 

我们只需要判断,如果说 这个println方法执行,然后看他发过来的字符串的内容,如果是以Dispatching to开头的我们就去记录一个当前的时间 然后在接到Finished to 方法 我们也去记录一下当前时间,然后将这两个时间相减我们就得到 193 msg oncreate的方法 执行的耗时

Looper方案

 这就是 (BlockCanary)实现原理,借助的就是handler looper 它可以让我们监控到每一次将dispatchMessage 每一次这个消息执行的耗时,我们的 oncreate方法 点击事件执行的方法 都能够通过looper机制 监听到他的耗时时间

我们的阈值设置为5s,如果两个时差超过了5秒 认为程序出现了卡顿 这时候我们可以利用

Thread#getStackTrace的接口来拿到我们当前卡顿的时候 我们的方法 我们的程序正在执行哪些方法。这就是捕获我们卡顿的时候执行的堆栈信息,从而去分析我们卡顿问题的原因 

 除了(BlockCanary使用handler机制以外,(ArgusAPM支持360的,LogMonitor)依赖的Choreographer编舞者模块

view的绘制流程 Android屏幕刷新时多长时间? 60hz 16毫秒的样子

60hz 16毫秒系统会发出vynsc信号 刷新信号发出之后  我们的Android 系统当中

 Choreographer可以监控系统底层发出来的vynsc信号 监听到vynsc信号之后,就会处理ui的绘制,处理输入 动画 绘制的操作 换句话来说Choreographer可以监听到vynsc信号

正常来说两次vynsc信号间隔16毫秒左右,如果两次vynsc信号中间 绘制操作 绘制操作  你花了太长的时间,导致你下一次接到的信号跟上一次接到的信号超过了16毫秒,那就可能意味着 你这一次的绘制操作超时了,

 这个方法 我们在刷新UI的时候 会执行ViewRoot mpl中的方法,这个方法 他用到了handler机制

 利用handler 发出了一个消息屏障

Linux的epoll机制也是handler的一个知识点

把我们的同步任务暂停掉 因为他要优先进行UI的绘制 让UI的绘制是优先的

用mChoreographer.postCal1back(就是去注册一个监听 监听我们的vynsc信号

怎么利用Choreographer完成卡顿的监控呢?

注册一个callback,系统发出一个新的信号之后,就会由系统回调 我们这个callback 那这样的话我们接到一次callback的时候 也是去记录一下当前时间,然后再来继续去注册callback 那么 只要去在第二次接收到我们回调的时候,拿到我们第二次回调的当前时间,减去我们上一次接到的vynsc信号时间  把这个时间一减 最后得到一个时间差 如果这个时间差超过我们设定的阈值 比如说5秒,4秒 我们也可以

 获取我们发生卡顿的时候 我们程序 正在调用方法的堆栈 从而把这些信息记录下来 给我们去分析我们的卡顿问题

这个Choreographer就是ArgusAPM、LogMonitor的实现原理

matrix :对这两种方案都有应用,但是他还做了

 

这是我们的plootcamov 当他监听到卡顿的之后, 给我们采集到的系统的信息 cpu信息  还有我们当前正在执行的堆栈信息,

 mainactivity 有个click方法 ,click调用test1方法 test1又调用test2 这时候我们的程序出现了卡顿,通过这个 plootcamov采集到的异常堆栈 卡顿堆栈 告诉我 你们觉得我们当前代码哪里出现了代码卡顿? test2导致我们程序出现了卡顿,

 其实不一定是test2 可能是test1  或者说test2调了一个方法  a方法 b方法 调用了100个方法

那么你能不能 通过这个卡顿的代码准确的定位到 我们的卡顿到底是在test1 还是test2? 是test2里面的a方法? b?c?显然不行

没办法获取到各个函数的执行耗时3.Matrix卡顿监控,耗时如何获取?

matrix出现了输入 trace 出现了卡顿,这个卡顿  告诉我们卡顿信息 以及 cost  耗时时间  stack定义的规则

matrix怎么做到的?

反编译工具 

有jvmti为什么还要 用插桩 

methodentry
methodexit 监听方法的进入以及退出

jvmti以后是性能监控的方向,因为现在Android8以的设备还有很大的市场的,没法支持Android8以下的设备,这就是为什么我们要学字节码插桩的原因

 所有的方法都要插入这样的代码 插桩 

字节码插桩 就是在字节码里面写代码

 .java写的是字符串

.class  掌握哪些知识点? class 字节码

指令:

dup
store
load
sub
invokestatic

为什么要学习字节码指令?

 大厂面试👆 并发问题,肯定不是怎么用?

 

字节码指令  

invokestatic 执行一个静态方法 

monitorenter 进入synchronized代码块 monitorexit:退出 synchronized代码块 

虚拟机遇到这个指令的时候,就要去帮我们保证代码的同步

synchronized的原理的话,还要涉及到看,你锁的是class, 还是实际对象 又有区别

对象有对象头,会记录锁的状态的 轻量级锁 重量级锁 偏向锁  synchronized的原理还要学习更多相关jvm的知识

 锁膨胀 是怎么膨胀的

ASM框架

 

asm:框架
ams:android

 

 

 

 

 

 Classvisitor 类的访问者,其实就是setonclicklistent 设置一个回调监听一样 

 init代表无参的构造方法

ClassVisitor类的访问者 只能访问类 类当中定义的属性 方法,但是我们要访问 方法体 不好意思ClassVisitor无法访问方法体 类访问者只能让你知道 这类当中有哪些方法的存在,方法的作用域是不是static的 但是你要了解 内部的内容 那不好意思  你要用MethodVisitor方法访问者才能够访问到方法体 要进入到方法内部 在方法体里面插入我们的代码

AdviceAdapter是MethodVisitor的子类,这个类的作用 他可以帮助我们进行更加简单的方法封装 让我们使用起来更加的简单

 传参:asm的版本号

可能是装饰者模式 可能是代理 模式 都有可能 也有可能是责任链模式 你需要具体确定他是什么设计模式的话,你必须去了解methodVisitor交给我们MyMethodVisitor干了什么事情  代理模式跟装饰者模式的区别是什么? 都是行为型模式  代理侧重控制  装饰者重视简化 增强

MyMethodVisitor为什么要有一个 我们还要把super的methodVisitor传进去呢? 我们在进行字节码插桩 会不会有一种情况,我们不需要插桩 不需要class 我们只需要分析去采集数据,我们不需要对class进行修改,只需要去采集里面的数据 采集类的数据,采集方法体里面的数据  有没有这种可能?tinker 他就做了这个事情

当我们不需要修改class的时候 这个 methodVisitor他的作用是让我们最后得到的分析完之后 最后再来得到 我们分析完成处理完成之后的class 不变 让我们的class不变 如果我们要让我们的class发生变化呢?

  为什么用AdviceAdapter 因为他里面给我们定义了一个方法

这些方法的作用是什么?分别在什么时候回调?onMethodExit退出进入 执行一个方法,退出一个方法就回调,onMethodEnter(进入一个方法就会调用

也就是说,我们执行main方法,当他解析到main方法的第一行,当要开始解析方法里面的方法体的时候 就会给我们回调一次我们的onMethodEnter 解析完了所有的方法之后 要退出这个方法的解析的时候就会回调一次onMethodExit

monitorEnterdaib monitopExit代表同步代码块的进入与退出

invokestatic 调用静态代码块,---调用方法  lstdre_1压栈---保存返回值

 invokeStatic(1

 storeLocal()压栈 压本地的变量 到栈当中去

 index对应的本地变量

 这个返回值 他在栈顶我们调用完,这个方法之后他会得到一个返回值,这个返回值保存在虚拟机,虚拟机onMethod 每个方法对应有一个jvm内存模型 虚拟机 栈帧 栈帧里有java内存模型,jmm 有局部变量表  有操作树栈 有动态链接 等

我们调用invokestatic 这个方法,这个方法的返回值在哪里?就在我们的栈顶,然后我们newLocal 他就会把栈顶当中的值去storeLoca1把他invokestatic 的值赋值给了我们的 创建出来的本地变量

得到插桩的结果,需要new Classwriter

 

 

 

 

 +为什么不是运算的作用,为什么是拼接的作用?通过字节码更加清晰的认识到+字符串操作是被谁进行了一次翻译?javac 会把它返回成stringbuilder 了解字节码可以让知识点更加的清晰,而不是人云亦云 你听说+加是stringBuilder

在中间插的话比较麻烦的,一般情况下不需要中间插 很难达到通用的效果,

怎么拿到所有的class 获取所有程序中的class 怎么拿 要用到 Gradle TransformAPI是一套api 它能够帮助我们去hook 我们编译打包过程 当作 拿到我们的所有的class文件

class转dex  

Matrix怎么完成插桩的,也是借助asm 然后借助transform 拿到所有的class文件 内部再借助asm完成的插桩

classWithInject 自己写的插件

 完成了这些事情👇

 transform作用就是拿到所有的class 

完成插桩后,还要做一件事情,数据收集 日志 mmap +压缩 加密 

sdk闭源 activity 调用a()->dialog.show()

需求 service:a()->崩溃 没问题 我们不改 谁让你在service:a调用? 

用asm帮他去结合gradle 写了一个脚本,原始的

main方法有个thread.sleep方法 

main方法里面没有代码了👇

 我可以用这种一样的原理,把dialog.show 抹除调,如果要显示我去加一个代码 给dialog.window.set.. 设置一个属性 

Android深入卡顿分析与实践
https://mp.weixin.qq.com/s/QJufTPSqDIFNYOnlZQfbJw

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值