1.发现内存泄漏问题
在项目开发中,我使用了高德地图SDK,实现了类似微信位置选择的功能。最近在完善项目时,发现了一个一直未能解决的内存泄漏问题的解决方法。
2.排查原因
起初,我尝试使用如下代码来销毁引用:
这些销毁代码都是在内存泄漏提示后逐一添加的,有些变量即使在onDestroy
中不设置为null
也没有问题。尽管我销毁了能想到和能查到的所有对象,问题依然存在。无奈之下,我暂时放弃了。
最近,在处理其他内存泄漏问题时,我对内存泄漏的原理和解决方法有了更深的理解,并学会了使用Android Profiler分析LeakCanary生成的Heap Dump文件。于是,我再次分析了之前的地图内存泄漏文件,如下所示:
结合网上资料和自己的理解,我判断是长生命周期对象持有对短生命周期对象的引用。既然我已经销毁了所有可能的引用,问题可能出在销毁顺序上。 我重新查看了这些对象的初始化过程,如下图所示:
可以看到,aMap
是通过mapView.map
初始化的,而mapView
对应onDestroy
内的mDatabind.map
。在销毁顺序上,先销毁aMap
再销毁mapView
,导致aMap
无法真正释放,即使mapView
销毁后,仍持有对aMap
的引用。
3.原因分析
- 内部引用关系 :
MapView
内部持有aMap
的引用。如果先调用aMap?.clear()
和aMap=null
,再调用mapView.onDestroy()
,可能导致MapView
在销毁时仍然持有对aMap
的引用,导致内存泄漏。 - 资源释放顺序 :
aMap?.clear()
和aMap=null
用于清理aMap
相关的资源,而mapView.onDestroy()
用于销毁MapView
。如果先销毁MapView
,则MapView
内部持有的aMap
相关资源也会被清理,这样再清理aMap
就不会产生问题。
4.解决方法
在销毁aMap
前先销毁mapView
,确保引用的aMap
得到释放。
5.总结
排查内存泄漏原因时,要考虑对象间的引用关系;解决内存泄漏时,要按照正确顺序销毁资源对象。通过这次解决经验,也让我学到了如何更好地管理资源的生命周期,避免内存泄漏问题。
本文参考链接:
查找内存泄漏问题时读过该文章,本文模仿了其行文风格