前提
以前面试中,面试官问到我优化了那些点。我当时紧张,只回答了说一个日期格式化的优化。所以从这个经历来说,我个人对自己做过的优化没有总结,优化的方法没有仔细地考虑原因,以及这个优化会有什么其他的副作用。今天特意来总结,因为最近学习了JVM内存布局、并发、锁等方面的知识,通过这些知识来更好的理解当初的优化方法。当初优化通过工具分析到卡顿点,找出了优化方法,而没有分析为什么这样优化会达到效果。
短信应用是android原生应用,平台是MTK android o的代码。短信中存储了5000条短信(通过工具批量插入)。
问题:滑动(快慢)短信列表会出现帧率小于60fps.
分析
- 首先我们使用systrace工具,查看是否有卡顿现象。测试人员是通过高速摄影机来判断丢祯率。那么我们开发人员通过systrace工具来查看到底是在那个环节耗时比较多。
通过上面的图可以看出,短信应用在滑动时确实耗时偏高。我们查看其中一祯:
工具的分析结果是建议我们提高适配器的getView绑定数据的效率。从这个建议当中我们无法确切的知道问题出在哪行代码上,之所给我们一个大概的方向。通过systrace工具能够让开发人员检测界面是否有卡顿,给出一个指导意见。在特别小的差别面前,我们人的感知是无法区别的。
- Method Profiling 方法分析工具
因为systrace无法定位到确切的代码。还好我们有Method Profiling 工具可以分析方法的执行情况。理论上可以通过打印时间戳来追踪耗时方法,但是这个方法比较费事。
在android device monitor工具中点击“start Method Profiling”,开始检测->滑动短信列表->“stop Method Profiling”,
那么上面的图中,我们如何找到耗时方法呢?可以在过滤器中输入我们的包名,这样,我们的耗时类就在最上面了。
第一个耗时高的方法是Conversation.from();我们再点击进去,发现是Conversation中的内部类Cache.put方法耗时非常多。而Cache.put方法是间接调用了ConcurrentHashMap.put方法。HashMap添加元素的步骤是,根据key的hash散列码来放到桶中。如果桶中没有元素则将元素放到这里,如果有值,则比较是否是同一个元素,是则更新,否则在后面添加(分离链接法)。最终发现是equals方法耗时较多。那么我看一下Conversation的equals方法是如何实现的。