1、动态dump
1) Native C++版本
#include <utils/CallStack.h>然后使用CallStack类
2) Java版本
Exception e = new Exception("dumpinfo");
e.printStackTrace()
//或者
Log.w("tag", Log.getStackTraceString(new Exception()))
2、卡顿
1) adb shell dumpsys
adb shell dumpsys SurfaceFlinger
adb shell dumpsys gfxinfo
2) 利用UI线程的Looper打印的日志
Looper.loop()中,dispatchMessage前后会打印日志
Looper.getMainLooper().setMessageLogging(new Printer())
打印UI线程的堆栈信息
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
for (StackTraceElement s : stackTrace) {
sb.append(s.toString() + "\n");
}
Log.e("TAG", sb.toString());
可以在日志打印前后,也就是监控加入和移除之间,进行高频的采集堆栈信息。
一般来说,一个卡顿是否发生的耗时阈值是80ms(5*16.6ms),
当一个卡顿达80ms的耗时,采集1~2个堆栈基本可以定位到耗时的堆栈。
采样堆栈的频率我们设为52ms(经验值)。
高频采样会带来海量的堆栈数据,通常卡顿点dump出的都是一样的堆栈;
可以做hash处理,排重去重减少数据量。
3) 利用Choreographer.FrameCallback监控卡顿
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback())
Android系统每隔16ms发出VSYNC信号,来通知界面进行重绘、渲染,
每一次同步的周期为16.6ms,代表一帧的刷新频率。
当每一帧被渲染时会触发回调FrameCallback,
FrameCallback回调doFrame(long frameTimeNanos)函数。