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)函数。
3、反射
1) 反射获取类的成员变量
onPause的时候,在每一帧打印出主线程消息队列中的所有消息
private Field messagesField;
private Field nextField;
{
try {
messagesField = MessageQueue.class.getDeclaredField("mMessages");
messagesField.setAccessible(true);
nextField = Message.class.getDeclaredField("next");
nextField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
Choreographer.getInstance().postFrameCallback(this);
Log.d(TAG, "doFrame");
printMessages();
}
});
}
}
private void printMessages() {
MessageQueue queue = Looper.myQueue();
try {
Message msg = (Message) messagesField.get(queue);
StringBuilder sb = new StringBuilder();
while (msg != null) {
sb.append(msg.toString());
sb.append("\n");
msg = (Message) nextField.get(msg);
}
Log.i(TAG, sb.toString());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}