Android 性能优化梳理

目录

目录

1、内存泄露优化

1.1 抓取内存泄露方法

2、启动优化

2.1、冷启动

2.1.1 抓取冷启动方法

2.2、热启动

2.2.1 抓取热启动方法

2.3 启动优化 

3、卡顿优化

3.1、CPU占用查询

3.1.1 通过脚本命令抓取CPU占用

3.1.2 抓取trace文件

3.1.3 CPU分析

3.1.4 通过perfetto工具或者systrace分析trace文件

3.2、内存占用分析

3.2.1 通过脚本命令获取内存

3.2.2 抓取trace文件

3.2.3 内存分析

3.3 卡顿分析

4、性能抓取命令总结

5、抓取CPU和内存脚本命令


1、内存泄露优化

1.1 抓取内存泄露方法

方法一(适用于右发际线高着使用):

1、执行dumpsys meminfo ‘包名’记录当前内存占用

2、执行压测脚本循环遍历业务功能

3、压测一段时间后退出界面等待一段时间后输入命令:dumpsys meminfo ‘包名’查看Activities是否为0,内存有无明显增加的情况

方法二(适用于左发际线高着使用):

通过Android Profile抓取内存快照查看是否有内存泄露

1、使用Memory Profile实时跟踪应用的内存信息,针对内存分配异常的情况,可以通过抓取内存快照进行分析

2、点击Profile的Memory显示条即可进入Memory Profile

 

2、启动优化

2.1、冷启动

2.1.1 抓取冷启动方法

方法一:通过串口命令获取

  1. 在测试前先查询进程是否存在 命令 ps -A | grep 包名
  2. 如果进程存在则需要杀死进程使用 命令 kill -9 进程号
  3. 在杀死进程后在使用启动命令查看启动时间 命令am start -W 包名/类路径名

应用自身启动耗时,参考TotalTime;

系统启动应用耗时(包含上一个应用activity的pause),参考WaitTime;

方法二:抓取trace判断启动时长

分析冷启动时间:定位到当前应用的UI Thread,如下图,从ZygoteInit到serviceStart后的第一帧结束,查看时间长度做为启动时长(注意该时长比应用测试部用视频采集卡采集的时间要短,视频采集卡采集的是用户感知的真正时长,我们这里的时长仅用作自己应用启动时长分析);

2.2、热启动

2.2.1 抓取热启动方法

方法一:通过命令抓取

  1. 让应用退出前台
  2. 在测试前先查询进程是否存在,如果存在在进行下步操作 命令 ps -A | grep 包名
  3. 使用启动命令查看启动时间 命令am start -W 包名/类路径名

方法二:抓取trace判断启动时长

 分析热启动时间:定位到当前应用的UI Thread,如果是activity进入,则从activityStart到serviceStart后的第一帧结束,查看时间长度做为启动时长。

如果是service进入,则从serviceCreate到serviceStart后的第一帧结束,查看时间长度做为启动时长。

2.3 启动优化 

启动我们可以查看是否Application初始化或者Activity初始化时存在耗时,可以做出如下改善

ContentProvider:

ContentProvider的onCreate方法会在Application的onCreate方法前执行,其onCreate方法不要放耗时操作,可以通过Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler()延时加载

Application层面:

  • 将Application的onCreate方法中第三方SDK初始化放入线程中处理
  • Multidex预加载优化,5.0以下多dex情况

Activity层面:

  • 首屏Activity的渲染不要有耗时操作,如果有可以放入子线程或者IntentService中处理
  • 预创建Activity,对象预创建
  • 预加载数据

UI层面:

  • 消除启动时的白屏、黑屏。windowbackground
  • 避免布局嵌套,多层嵌套

编译层面:

  • ART 如何编译 DEX 代码还有个compile filter以参数的形式来决定:从 Android O 开始,有四个官方支持的过滤器:
  1. verify----只运行 DEX 代码验证。
  2. quicken----运行 DEX 代码验证,并优化一些 DEX 指令,以获得更好的解释器性能。
  3. speed-profile—运行 DEX 代码验证,并对配置文件中列出的方法进行 AOT 编译。
  4. speed----运行 DEX 代码验证,并对所有方法进行 AOT 编译
  • verify 和quicken 他俩都没执行编译,之后代码执行需要跑解释器。而speed-profile 和 speed 都执行了编译,区别是speed-profile根据profile记录的热点函数来编译,属于部分编译,而speed属于全编。
  1. 执行效率:verify < quicken < speed-profile < speed
  2. 编译速度上:verify > quicken > speed-profile > speed
  • 查看应用编译状态:dumpsys package 包名 | grep status
  • 串口修改编译状态:pm compile -m speed 包名

参考:启动优化

3、卡顿优化

3.1、CPU占用查询

3.1.1 通过脚本命令抓取CPU占用

1、定义脚本文件gen_memory.sh(代码在第五章节),修改包名和U盘挂载路径

2、将gen_memory.sh拷贝到/data/目录,赋权限777(chmod 777)

3、运行脚本(进入到data目录后输入 ./gen_memory.sh),然后遍历各选项功能;

4、退出应用,然后运行脚本(进入到data目录后输入 ./gen_memory.sh);

5、等待一段时间后,建议10分钟以上,拔出U盘,查看U盘中指定包名文件夹下的cpu.csv文件,进行分析查看内存占用是否合理。

3.1.2 通过TOP命令抓取CPU占用

分析系统和进程的CPU占用情况:top -m 20 -n 1 (输出一次cpu占用前20的所有进程数据)

分析高占用进程的线程CPU实时占用情况:top -Hp1635 -m 20 -d 1(输出pid为1853 的进程中cpu占用前20的线程数据,一秒一次)

技巧:同时开两个cmd窗口,分别输入命令同时监控进程和线程的实时占用,可定位到线程,可做成脚本控制频率,动态采集高占用的进程,再结合业务逻辑做归因分析。

3.1.3 抓取trace文件

1、通过脚本命令抓取trace

抓取10秒内trace:

atrace -z -b 10000 gfx input view wm am res dalvik rs sched freq idle disk binder_driver binder_lock -t 10 > /data/trace_output1.atrace

持续抓取:

开始抓取 atrace --async_start -c -b 12800 -z gfx view input webview wm am sm audio video camera hal dalvik res rs bionic pm ss database network disk sched freq idle binder_lock binder_driver

复现到后停止 atrace --async_stop -c -b 12800 -z -o /data/local/tmp/trace.out

2、通过profile抓取trace

3.1.3 CPU分析

CPU Profile可以跟踪如下几种数据:

  • Sample Java Method 为间断采样,适用于大部分情况,profile调试不会对现有程序造成影响
  • Trace Java Method 持续采集,适用于跟踪全部method执行状况,会对现有程序运行造成影响
  • Sample C 跟踪C层函数(Android 8.0+)
  • Trace System Call 跟踪系统调用,如核心运行状态和掉帧情况( Android 7.0+)

3.1.4 通过perfetto工具或者systrace分析trace文件

systrace是google 提供的一个分析工具,脚本命令为Android SDK的platform-tools\systrace\systrace.py , 它的运行依赖python2.7+,所以在进行trace分析前需要安装python对应环境。

转换命令:python "D:\Program Files\Android\sdk\platform-tools\systrace\systrace.py" --from-file=D:\9615_trace\trace008.out 

我们可以从frame看出是那一帧卡顿,红色是验证卡顿、橙色为轻微卡顿、绿色不卡顿。然后再从堆栈分析draw、layout的耗时情况。

 线程状态

绿色:正在运行,线程正在完成与某个进程相关的工作或正在响应中断。

蓝色:可运行,线程可以运行但目前未进行调度。

白色:休眠,线程没有可执行的任务,可能是因为线程在遇到斥锁定时被阻止。

橙色:不可中断的休眠,线程在遇到 I/O 操作时被阻止或正在等待磁盘操作完成。

紫色:可中断的休眠,线程在遇到另一项内核操作(通常是内存管理)时被阻止。

3.2、内存占用分析

3.2.1 通过脚本命令获取内存

1、定义脚本文件gen_cpu.sh(代码在第五章节),修改包名和U盘挂载路径

2、将gen_cpu.sh拷贝到/data/目录,赋权限777

3、运行脚本(进入到data目录后输入 ./gen_cpu.sh),然后遍历各选项功能;

4、退出应用,然后运行脚本(进入到data目录后输入 ./gen_cpu.sh);

5、等待一段时间后,建议10分钟以上,拔出U盘,查看U盘中指定包名文件夹下的meminfo.csv文件,进行分析查看内存占用是否合理。

3.2.2 通过TOP命令抓取内存

技巧:1,先使用命令dumpsys meminfo查看设备的内存占用情况,分析内存不足时各个进程的占用,这个命令统计时间较长,比较耗资源,不适合频繁使用

2,使用命令dumpsysmeminfopkg/pid查看对应进程的详细内存分布,用于前期初步分析定位内存的分布:

  • Native Heap 较高时,一般是Bitmap对象较多(结合Views判断);或者是JNI里C/C++申请的对象占用内存较多
  • Java Heap 较高时大部分占用都是应用程序里的申请的对象内存,抓取内存快照可详细分析
  • Code 较高代表so库,jar包数量多;代码量大,大量的类加载(多个class.dex分包),资源多等原因,可解压apk查看,需要关注apk瘦身优化
  • Stack 占用高通常是线程数量多太,栈内存高导致,检查无用线程,尽量用线程池创建线程Graphics 是UI渲染任务繁重,检查Views层级,过度绘制,注重图层优化
  • System 是可系统相关的内存,可能是使用较多的系统服务,应用程序框架等原因
  • 通过Activites数量持续增加/退出后不减少的情况,可以初步判断内存泄漏

3.2.2 抓取trace文件

1、通过脚本命令抓取trace

抓取10秒内trace:

atrace -z -b 10000 gfx input view wm am res dalvik rs sched freq idle disk binder_driver binder_lock -t 10 > /data/trace_output1.atrace

持续抓取:

开始抓取 atrace --async_start -c -b 12800 -z gfx view input webview wm am sm audio video camera hal dalvik res rs bionic pm ss database network disk sched freq idle binder_lock binder_driver

复现到后停止 atrace --async_stop -c -b 12800 -z -o /data/local/tmp/trace.out

2、通过profile抓取trace

3.2.3 内存分析

内存分类:

  • Java表示Java代码或Kotlin代码分配的内存;
  • Native表示C或C++代码分配的内存(即使App没有native层,调用framework代码时,也有可能触发分配native内存);
  • Graphics表示图像相关缓存队列占用的内存;
  • Stack表示native和java占用的栈内存;
  • Code表示代码、资源文件、库文件等占用的内存;
  • Others表示无法明确分类的内存;

3.3 卡顿分析

Systrace会统计卡顿的具体类型,一般常用的类型有:

1、CPU分配不足:

进程大部分处于Runnable,CPU资源分配不足

  • Scheduling delay:调度延迟
  • Expensive measure/layout pass:绘测或者布局时间长
  • Long View#draw: view 绘制时间长 

导致卡顿可能有如下原因:

  • 过于复杂的布局
  • UI线程的复杂运算
  • 频繁的GC,如内存抖动,即大量的对象被创建后又短时间被回收,或者瞬间产生大量的对象会严重占用内存区域

4、性能抓取命令总结

方式命令
帧率

dumpsys gfxinfo 包名

丢帧率:Janky frames的前后差值 / Total frames的前后差值
平均帧率= 60-(60*丢帧率)

内存泄露、内存占用

dumpsys meminfo 包名
查看前20个进程的cpu使用top -m 20
应用安装大小du -sh  安装路径

5、抓取CPU和内存脚本命令

#!/system/bin/sh
#设置包名
packagename="";
#设置U盘路径
path="/mnt/media_rw/2DD0-A606/$packagename";
#设置du与dumpsys的间隔时间
sleeptime=15
#设置top间隔时间,建议15秒以上
toptime=15
a=0
b=0
c=0
d=0
#设置总次数
total=100000
#设置常量
u=1024
#v=6
if [ ! -d "$path" ]; 
then 
mkdir $path
else 
rm -rf $path
mkdir $path
fi ;
#查看Android版本
v=$(getprop|grep ro.build.version.release |awk '{print$2}'|awk '{print substr($1,2,1)}');
echo $v >> $path/android_ver.csv ;
#获取CPU个数
processor=$(($(cat /sys/devices/system/cpu/possible |awk -F'[-]' '{print$2}')+1));

#生成ddr表的表头
echo  -n "time," >> $path/meminfo.csv;
echo  -n "meminfo," >> $path/meminfo.csv;
echo  "Activity" >> $path/meminfo.csv;
#生成cpu表的表头
echo  -n "time," >> $path/cpu.csv;
echo  -n "cpu," >> $path/cpu.csv;
echo  "Activity" >> $path/cpu.csv;


while (($b < $total));do 
let "b += 1";
if [  -d "$path" ]; then 
echo -n $(date "+%H:%M:%S,") >>$path/meminfo.csv;
#echo -n $(date "+%H:%M:%S,") >>$path/ddr.csv;

#输出Meminfo大小 单位:M
ddr=$(dumpsys meminfo $packagename |grep TOTAL |awk 'BEGIN{ddr=0}{ddr += $2}END{print ddr}');
echo -n "`awk -v ddr=$ddr -v u=$u 'BEGIN{printf "%.2f",ddr/u}'`," >>$path/meminfo.csv;
#获取当前Activity
echo $(dumpsys window |grep  mCurrentFocus |awk '{print$3}'|awk -F "}" '{print$1}') >>$path/meminfo.csv;
sleep $sleeptime;
fi ;
done&
while (($c < $total));do 
let "c += 1";
if [  -d "$path" ];then 
#CPU
    cpu=$(top -b -n 1|grep $packagename|awk 'BEGIN{cpu=0}{cpu += $9} END {print cpu"%"}');
    echo -n $(date "+%H:%M:%S,") >>$path/cpu.csv;
    #生成CPU占用
    echo -n "`awk -v cpu=$cpu -v processor=$processor 'BEGIN{printf "%.2f%%",cpu/processor}'`," >>$path/cpu.csv;
    #获取当前Activity
    echo "`dumpsys window |grep  mCurrentFocus |awk '{print$3}'|awk -F "}" '{print$1}'`," >>$path/cpu.csv;
    sleep $toptime;
fi ;
done&
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值