性能优化-卡顿

性能优化-卡顿

卡顿
线上监控方法:
方法1:Coreographer帧率检测,postFrameCallback ,保存两次 doFrame 时间进行相减然后除以刷新频率,这样算出来的结果就是两次 doFrame 的掉帧数

方法2:Looper设置print ,匹配消息分发前后字符串,计算之间的耗时

方法3:开启个线程循环通过主线程Handle,post一个延迟x秒的消息去修改一个值,睡眠x秒后在去看下这个值是否修改了

线下监控方法
1、利用Systetrace工具

1
systrace.py -a com.duowan.gamevoice sched freq idle am wm gfx view binder_driver hal dalvik camera input res

只要带上sched 就可以看到自定义的beginSection

2、profile traceView 打印出详细调用堆栈
profile 手动记录时间段
指定监控方法,通过代码自定义开始和结束,有的文件分析不了可能是后面参数设置太小了,文件写的不全

1
Debug.startMethodTracing("/sdcard/gameVoiceMethodTrace_app",1024*1024*20);

3、系统自带工具 StrictMode
避免主线成io耗时操作
使用StrictMode 检测主线程是否有io,网络等耗时操作会打印到logcat中

// 启用 StrictMode
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
        .detectAll() // 检测所有问题
        .penaltyLog() // 输出问题信息到日志
        .build();

    StrictMode.setThreadPolicy(policy);

4、第三方工具:BlockCananry

ANR

  1. 什么是ANR?
    当应用程序在一段时间内未能响应用户输入或系统事件时,Android系统会主动生成ANR错误
    ANR一般有以下几种类型,具体数值

    • KeyDispatchTimeout:按键事件在5s的时间内没有处理完成。

    • BroadcastTimeout:广播接收器在前台10s,后台60s的时间内没有响应完成。

    • ServiceTimeout:服务在前台20s,后台200s的时间内没有处理完成。

      主线程阻塞,广播接收器处理耗时,服务未响应,服务执行耗时任务,主线程死锁等都可能会导致ANR

      但并不一定主线程耗时任务就会出现anr如下面这种情况,如果后续没有事件需要处理是不会产生anr的
      8a0823ee154241d9d1a8c25671cd2058

  2. ANR如何监控
    方法一:6.0 以下手机监听 用FileObserver 监听/data/anr/trace.txt 文件,变化了之后调用AMS 获取进程状态,getProcessesInErrorState

    方法二:6.0 以上获取 通过jni 调用 sigaction 注册监听 SIGQUIT信号,然后在去AMS查询状态。signal 3信号就是ANR

    方法三:直接定期轮训查AMS的状态

    方法四:AnrWatchDog,原理:开启个线程循环通过主线程Handle,post一个延迟x秒的消息去修改一个值,睡眠x秒后在去看下这个值是否修改了,没有判断为ANR,还可以查询小AMS状态二次校验下。非侵入式,不需要hook

  3. ANR trace文件获取
    线下收集trace文件

    1
    2
    #适合6.0 以下
    adb pull /data/anr/trace.txt

线上收集trace,
通过sigaction 设置个signalHandler

5d1cb110e2b99a3a802b6253b08b2331

25b204164d9e7690496f1803597bbab2

Xhook hook write 函数拿到trace文件,这个文件包含很全面的anr信息
9c38971886e1c4b71365960bc3769841

1
2
#适合6.0以上,没有权限获取了
adb bugreport
崩溃异常辅助日志搜集
/system/bin/logcat 手机自己的日志工具,也可以用adb locat
1
2
3
4
5
6
7
8
9
10
11
#查看崩溃日志缓冲区(默认)
/system/bin/logcat -b crash

#查看系统系统事件缓冲区消息
/system/bin/logcat -b events

#查看主要日志缓冲区(默认),不包含系统和崩溃日志消息。
/system/bin/logcat -b main

#查看系统日志缓冲区(默认)
/system/bin/logcat -b system
通过popen获取得到输入命令文件,然后fgets读出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char* types[] = {"crash", "system", "events", "main"};
int lines[] = {10000, 5000, 5000, 10000};
CrashLogWriter::GUIDInstance()->WriteLogFormat(
"logcat %s", SEGMENT_BEGIN);
for (int i = 0; i < 4; i++) {
char cmd[128];
FILE *fp;
char buf[1025];
snprintf(cmd, sizeof(cmd), "/system/bin/logcat -b %s -d -v threadtime -t %u -d *:D",
types[i], lines[i]);
if(NULL != (fp = popen(cmd, "r")))
{
buf[sizeof(buf) - 1] = '\0';
while(NULL != fgets(buf, sizeof(buf) - 1, fp))
CrashLogWriter::GUIDInstance()->WriteFile(buf);
pclose(fp);
}
CrashLogWriter::GUIDInstance()->WriteLogFormat("tail of %s %s", types[i], SEGMENT_END);
}

功耗优化:
SurfaceView 替换 TextureView
CPU 数据上看,SurfaceView 要比 TextureView 优化 8%-13%
功耗数据上看,SurfaceView 要比 TextureView 平均功耗低 20mA 左右。

硬件绘制,代替软件绘制
视频硬编解替换软编解
减少过度绘制
减少刷新区域
减少刷新频率
CPU负载优化
长链接心跳
GSP