版权声明:本文章原创于 RamboPan ,未经允许,请勿转载。
记录一次使用 Android Profiler 分析内存
最近一个老项目需要更新,就想着把之前搜集的一些小问题一起修复了,然后测试了下,发现了一个情况,就是在查看历史数据模块的时候,进入比进入其他模块时间稍微长一点,想着优化下。
点击可能有点暗,
gif
上看不出来,我点击的时候水波触发暂停,还是能感觉间隔有点长。
看代码前怀疑是不是读数据库时有点缓慢,在代码中加入日志观察,发现读数据库并不缓慢,在大量代码中如何快速查找可能耗时的部分呢,想到了之前
AS
中
Profiler
可以查看内存的情况,当时也有一些其他参数,甚至在 8.0 上的系统也支持电量查看,那么此时我们就可以试试这个好用不。
一般会自动出现在常用的工具栏附近,可以看到是一个类似仪表指针的图标,没有的话,可以在上方菜单栏中查找。
点击之后将程序跑起来,下方菜单栏会出现
Profier
对话框,依次是
CPU
、
Memory
、
Network
、
Energy
,显示需要查看的几个选项,这里我们选择
CPU
。
这里会显示线程有关的,但是我们重点不是观察线程,是查看点击之后进行了哪些操作导致时间花费比较高,所以等程序进入主界面一会后,
CPU
慢慢稳定之后,点击
Record
,再点击我们要测试的模块,进入模块之后再点击一次
Record
位置(此时显示为
Stop
),那么就会得出一段分析的区间。
可以看到这种时间段,从上到下依次是调用的方法以及层级关系。
-
橙色部分是
Android
系统的方法。 -
蓝色部分是
Java
的方法。 - 绿色部分是我们的代码。
比如沿着左边的分支可以看到显示
Android
的方法调用,触发了
java.lang.reflect.Method.invoke
,再回到
Android
的代码调用最后走到我们的代码,因为
getLocalDate
中涉及一些数据处理,实现部分也是
Android
,
Java
的代码,所以最后末端变成橙色和蓝色的时间小块。
我们重点观察是图中绿色部分,特别是整块的绿色。图中能看到的有我们类的 onCreate 方法,中间一整块部分下方也有我们的方法,只是此处没有截取到。
图中的包名部分因为显示区间太小,所以没有完全显示出来,这里可以滑动滚轮将时间精度放大,也可以把鼠标移上去可以看到显示的,那我们先来找一找这个方法有没有。
可以看到确实是能找到我们对应的方法,但是检查了下这里面代码,里面时间优化的空间不大,那我们看有没有其他大的耗时部分,我们把界面往下拉一下。
可以看到这里有几个词语反复出现,感觉真相可能在这,我们放大来看一看。
移到对应的时间块上可以显示出时间,此时的缩放比例,我标出了一个图中方块的单位是
50ms
,可以发现中间有很多重复的调用,每个都是
50ms
左右或者更长,我看大概算了这几个绿色部分花了
1 .1
秒(流下了心痛的泪水),看来就是真凶没错,那我们按着这些方法来看一下问题出在哪了。
按着上图的指示,我们来查找这五个方法。首先是
instantiateItem
,再是
applyDataToView
。
接下来找剩下三个方法。
查看三处的代码。
可以看到一个共同的特点,都是在实现获得一个时间戳的字符串形式或者其中的部分。
先不说是否耗时,就逻辑上来说:如果需要反复用,在类里面加一个字符串的时间戳变量就行了,在保存
long
类型时间时,同时解出一个
String
类型的时间戳保存下来。
这还不是最气的,打开
DateUtils.dateToString()
这个方法。
这 …… 既然做成了静态的工具类,直接存一个静态的变量呀 …… 前人挖坑,后人踩坑。🙃
更详细的使用可以参考以下的链接 (需要科学上网)。