在我的应用程序的简化版本中,我有两个活动 A 和 B。活动 A 启动 B,并在完成一些工作后 B 调用 finish()。在大多数设备(运行 4.2 的 Galaxy Nexus、运行 4.0.4 的 Droid 4 和运行 2.3.4 的 Droid 2)上使用内存分析器工具都没有显示活动 B 的痕迹,这正是我所期望的。
但在运行 4.1.1 的 Samsung S3 上,由于到以下 GC 根的路径(排除弱/软引用),MAT 显示活动 B 对象仍然存在:
Class Name | Shallow Heap | Retained Heap
-------------------------------------------------------------------------------------------------
com.myCo.myApp.ActivityB @ 0x42720818 | 264 | 3,280
|- <Java Local> java.lang.Thread @ 0x4271cf60 Thread-21941 Thread| 80 | 52,264
|- mOuterContext android.app.ContextImpl @ 0x426adf68 | 104 | 784
| '- mContext android.media.AudioManager @ 0x428e49a0 | 48 | 152
-------------------------------------------------------------------------------------------------
每次我启动和停止活动 B 时,MAT 都会显示活动 B 内存占用的另一个实例。我打开/关闭活动 B 的次数越多,logcat 中报告的内存占用量就越大。通过 MAT 强制执行 GC 不会删除对活动 B 内存的引用。
我有三个问题。
为什么不同设备上的内存/GC 行为不同?
在 S3 上,操作系统最终会回来并 GC 搁浅的 Activity B 对象吗(换句话说,我不应该担心它吗,因为 Android 会在崩溃之前清理它)?
如果没有,Thread 和 AudioManager 引用从何而来,我将如何清除它们?
感谢所有经验丰富的“泄漏猎人”!
更新:为了查看活动 B 留下的“搁浅”内存实际上是否是一个问题,我在活动 A 和 B 之间创建了一个循环:
--- A calls startActivityForResult() on B
--- B calls finish()
--- onActivityResult() in A calls B again, etc...
我让它飞行了大约 15k 次迭代,程序没有崩溃。因此,即使此手机和操作系统版本(Samsung S3,4.1.1)上的 JVM 在内存中留下了对类 B 的引用,即使在 Activity B 调用 finish() 之后,似乎也有某种稍后的清理,因为在测试过程中,对 B 类的引用数量并没有单调增加。
事实上,我在测试期间生成了多个堆转储,并且从未看到过超过大约 100 个 B 类实例——而不是我期望在没有其他清理的情况下看到的 15k 个实例。 logcat 中的 GC 语句还显示内存使用量不断上升和下降,尽管活动 B 的调用量很大。
我的结论是,我不应该担心 finish() 调用后堆转储中是否存在 B 类引用,因为看来此手机/Android 版本上使用的 JVM 会进行某种延迟清理。
注意:这是我根据我运行的测试得出的推论,所以如果有人有不同的了解,请分享。谢谢!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)