Android性能分析是个老生常谈的话题,其意义不再赘述,下面直奔主题。
接下来是本篇章的重点,常用性能分析工具:
我们常用的有:TraceView、Systrace、系统跟踪(System Tracing)、Android Device Monito(Android Profiler),
首先声明:
TraceView已弃用!
TraceView已弃用!
TraceView已弃用!
原本的TraceView已经弃用了,现在是结合Android Studio 里面的Android Profiler使用的。AndroidSDK自带的工具,用来分析函数调用过程,可以对Android应用程序及Framwork曾代码进行分析。Android Studio 3.2 或更高版本,应改为使用CPU性能分析器来(见下文)
class WelcomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//开始记录针对当前页面的.trace
val dateFormat: DateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
val logDate: String = dateFormat.format(Date())
Debug.startMethodTracing(this.javaClass.simpleName + "_" + logDate)
setContentView(R.layout.activity_welcom)
Handler(Looper.getMainLooper()).postDelayed({
startActivity(Intent(this, MainActivity::class.java))
finish()
}, 500)
doSthInWelcome1()
doSthInWelcome2()
}
private fun doSthInWelcome1() {
Thread.sleep(20)
}
private fun doSthInWelcome2() {
Thread.sleep(25)
}
override fun onStop() {
super.onStop()
//结束记录
Debug.stopMethodTracing()
}
}
在startMethodTracing()的入参文件名是可选的,但如果未指定日志名称而再次调用startMethodTracing(),系统会覆盖已保存的日志,如果需要跟踪多个页面或者做比对,建议参考上述代码中修改日志命名方式
目标页面或代码执行后,就会生成.trace日志,直至stopMethodTracing
1 打开AndroidStudio DeviceFile explorer 找到日志文件,右键保存到电脑上
一般情况下系统会将日志文件保存到特定app的私有目录中(getExternalFilesDir() )返回的目录相同:sdcard/Android/data/example_package/files/name.trace
2.然后打开Android Studio的profiler打开本地文件
打开之后,就可以看到上述途中跟踪的日志
Debug api 我觉得方便之处在于可以单独统计任意页面,函数,而不会记录大量无关的函数,目标性强,不用费劲寻找目标代码
搭载 Android 9(API 级别 28)或更高版本的设备包含一个名为 System Tracing 的系统级应用。此应用类似于 systrace 命令行实用程序,但允许您直接从测试设备本身录制跟踪记录,而无需插入设备并通过 ADB 连接到该设备。然后,您可以使用此应用与开发团队共享根据这些跟踪记录得出的结果。
在解决应用中与性能相关的 bug(例如启动速度慢、转换速度慢或界面卡顿)时,录制跟踪记录特别有用。
启用开发者选项(如果尚未启用此选项)。
打开开发者选项设置屏幕。
在调试部分中,选择 System Tracing。此时会打开 System Tracing 应用,其中显示了应用菜单。
注意:上述添加快捷方式的步骤是可选的,仍然可以直接在开发者选项中直接使用此功能
调用android.os.Trace
的api进行记录
class WelcomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
doSthInWelcome1()
doSthInWelcome2()
}
private fun doSthInWelcome1() {
//自定义事件,参数用于标记区分当前事件:例如:WelcomeActivity-doSthInWelcome1
Trace.beginSection("doSth-1")
Thread.sleep(20)
//结束记录
Trace.endSection()
}
private fun doSthInWelcome2() {
//自定义事件
Trace.beginSection("doSth-2")
Thread.sleep(25)
//结束记录
Trace.endSection()
}
}
注意
:
- Trace.beginSection和endSection必须成对出现,可以嵌套;
- Trace.beginSection和endSection必须在统一线程中使用。
还有traceAsync可自行研究使用
图 4录制配置
可以看到,配置中可以配置跟踪的日志类型,录制文件大小等等,具体配置内容自行研究哈
图 3 启动设备上系统跟踪后出现的常驻通知
然后运行我们的app或关键页面,然后在通知栏点击通知或者快捷开关手动停止录制
录制结束后,把跟踪记录发送到电脑
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmYoAXwF-1661830582075)(D:\帖子\启动优化\system-tracing-share1.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N2ZkKJDx-1661830582075)(D:\帖子\启动优化\system-tracing-share2.jpg)]
在搭载 Android 10(API 级别 29)
或更高版本的设备上,跟踪文件会使用 .perfetto-trace 文件扩展名保存,并可在 Perfetto 界面中打开。在搭载较旧 Android 版本的设备上,跟踪文件会使用 .trace 文件扩展名(表示 Systrace 格式)保存。
可以使用ADB命令下载:
cd /path-to-traces-on-my-dev-machine
adb pull /data/local/traces/ .
然后使用Perfetto(.trace文件使用Android Profiler)打开该文件:
打开方式:
打开结果:
可以看到当前应用的各个线程的各个方法还有我们自定义的事件耗时;
图中具体代表的意义可以查看官方文档
Trace的api方便之处在于可以自定义函数跟踪,例如某一个插件某个类里面可以方便的根据入参区分,结果预览也很直观。
Systrace 允许你收集和检查设备上运行的所有进程的计时信息。 它包括Androidkernel的一些数据(例如CPU调度程序,IO和APP Thread),并且会生成HTML报告,方便用户查看分析trace内容。
Systrace 需要python2.7
环境,不支持python3,请自行官网安装python2.7并在安装的时候添加到环境变量;
同时需要确保已经配置android环境变量(将 android-sdk/platform-tools/ 添加到 PATH 环境变量),我已经配置了这个,又添加了systrace的环境变量,但还是提示找不到systrace.py文件,我只能从文件路径下执行了。。。
python systrace.py -o c:\\users\wilson\desktop\performance.html -t 10
参数解释:
- -o file 将 HTML 跟踪报告写入指定的 file。如果您未指定此选项,systrace 会将报告保存到 systrace.py 所在的目录中,并将其命名为 trace.html。
- -t N 跟踪设备活动 N 秒。如果您未指定此选项,systrace 会提示您在命令行中按 Enter 键结束跟踪。
更多参数请见官网命令行
跟踪结束,会在指定目录生成指定名称.html的跟踪结果,浏览器打开即可看到结果:
如图,箭头所指点开可以筛选可以看不同进程类型的日志。systrace面板不支持鼠标缩放,快捷键W-放大、S-缩小、A-左移、D-右移
更多使用方法介绍
请参考官网
需要注意,这种方式需要app存活才能记录
打开之后可以看到cpu、内存、网络的使用情况
点击上图中 cpu一栏
左侧集中记录方式区别:
选择其中一种开始记录,执行到目标代码之后,点击停止记录后,会自动打开结果如下图:
通过搜索,放大,可以看到我执行的点击事件(主线程sleep 25ms)
这样就可以看到我们的代码中各个方法的耗时,cpu占用情况,针对性优化
手机运行项目后,链接USB,profiler链接手机和项目,点击主屏幕右侧Memory一栏可以看到:
左侧record选项:
右侧显示的数据有:
1.我在代码里认为创造一个内存泄漏:
class MainActivity : AppCompatActivity() {
private val mBinding by lazy { ActivityMainBinding.inflate(LayoutInflater.from(this)) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.tvContent.setOnClickListener {
//跳转到其它页面并结束当前的页面
startActivity(Intent(this, ThirdActivity::class.java))
finish()
}
MLeakThread().start()
}
//非静态内部类
inner class MLeakThread : Thread() {
override fun run() {
while (true) {
Log.i(TAG, "onCreate: Thread")
SystemClock.sleep(20)
}
}
}
}
代码原理是通过一个内部类Thread持有当前Activity.点击事件跳转第三个页面之后结束当前页面
2.开始跟踪堆内存
2.1 运行代码(点击事件跳转)
2.2 左侧record选项选择堆转储方式
2.3 点击面板上部小垃圾筒Force GC 强制回收内存;
2.4 点击Record按钮
然后就可以看到下面的画面:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-glRg56uc-1661830582085)(D:\帖子\启动优化\profiler-capture.jpg)]
点击途中黄色感叹号,Leaks
:
如图所示:
1.点击leaks
2.可以看到mainActivity的实例本该被回收却仍然在,因为我主动写了一个内存泄漏,点击MainActivity
3.然后到-3-所指的地方,可以看到mainActivity的实例,点击它
4.右侧点击Reference
选项
5.点击Show nearest GC root only
6.底部Reference就看到发生内存泄漏时候所持有它的代码,点击`jump to source’
7.然后就自动打开了-7-所示的代码,就是我们内存泄露的地方。
以上是CPU 和内存方面优化工具以及方法的简单介绍,下期再讲UI方面的优化