返回

日常干bug系列:破解“mNewActivities”内存泄漏之谜

Android

在激烈的技术竞争中,寻找并修复bug是开发者永恒的使命。在这个日常干bug系列中,我将分享我亲历的bug追踪过程,揭秘幕后鲜为人知的故事。本次,我们聚焦于一个棘手的内存泄漏问题,直面其根源——“mNewActivities”。

最近在进行阿里云兼容性测试时,我注意到部分机器上的内存消耗异常。日志分析证实了内存泄漏的存在,于是我借助LeakCanary工具深入调查,最终锁定了问题根源——framework的内存泄漏。

按照惯例,我们怀疑是Activity类的泄漏。然而,进一步分析发现,问题的关键并非Activity本身,而是其内部持有的一个成员变量——mNewActivities。

mNewActivities是一个HashMap,用于存储最近创建的Activity实例。当Activity创建时,它会被添加到mNewActivities中;当Activity销毁时,它会被从中移除。但是,在我们遇到的情况下,某些Activity在销毁后没有被正确地从mNewActivities中移除。

造成这种异常行为的原因在于Activity销毁时的一种特殊情况。当Activity是通过startActivityForResult()方法启动的,并且其结果代码不是RESULT_CANCELED,则在Activity销毁时,不会触发其onDestroy()方法。这意味着mNewActivities中的Activity实例不会被移除,从而导致内存泄漏。

解决之道

要解决这个内存泄漏问题,我们采用了以下方法:

  1. 修改startActivityForResult()调用方式: 对于需要startActivityForResult()的场景,我们改用startActivityForResult(intent, REQUEST_CODE, options)方法,并在options中设置FLAG_ACTIVITY_CLEAR_TOP。这样,当子Activity销毁时,父Activity会收到onActivityResult()回调,即使子Activity的result code不是RESULT_CANCELED。
  2. 在onDestroy()方法中手动清除mNewActivities: 对于使用startActivityForResult()方法启动的Activity,我们在其onDestroy()方法中手动清除mNewActivities,以确保内存不会泄漏。

经验教训

这次的bug追踪经历带给了我们宝贵的经验教训:

  • 理解平台机制: 深入理解Android平台的Activity生命周期和启动模式,是解决此类内存泄漏问题的关键。
  • 谨慎使用startActivityForResult(): 了解startActivityForResult()方法的特殊行为,并根据实际场景谨慎使用。
  • 主动检测内存泄漏: 定期使用LeakCanary或类似工具检测内存泄漏,以主动预防性能问题。

通过不断解决此类问题,我们得以提升代码质量,增强应用稳定性。在下一期的日常干bug系列中,我们将探讨另一个令人头疼的bug故事。敬请期待!