1

在我的应用程序的简化版本中,我有两个活动,A 和 B。活动 A 启动 B,在完成一些工作后 B 调用完成()。在大多数设备上使用内存分析器工具(运行 4.2 的 Galaxy Nexus、运行 4.0.4 的 Droid 4 和运行 2.3.4 的 Droid 2)显示没有活动 B 的痕迹,这正是我的预期。

但是在运行 4.1.1 的三星 S3 上,MAT 显示活动 B 对象仍然存在,这是由于到以下 GC 根的路径(不包括弱/软引用):

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 内存的引用。

我有三个问题。

  1. 为什么不同设备的内存/GC行为不同?

  2. 在 S3 上,操作系统最终会回来并 GC 搁浅的活动 B 对象(换句话说,我应该不用担心它,因为 Android 会在崩溃前清理它)?

  3. 如果不是,那么 Thread 和 AudioManager 引用来自哪里,我将如何清除它们?

感谢任何有经验的“泄密者”!

4

1 回答 1

2

更新:为了查看活动 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 类的引用,即使在活动 B 调用了 finish() 之后,似乎也会进行某种稍后的清理,因为在测试期间,对 B 类的引用数量并没有单调增加。

事实上,我在测试期间生成了几个堆转储,并且从未看到超过 100 个 B 类的实例——与我希望看到的 15k 不同,如果没有其他清理。logcat 中的 GC 语句也显示了内存使用量的上升和下降,尽管活动 B 的调用数量很大。

我的结论是,我不应该担心在完成()调用之后堆转储中存在 B 类引用,因为在此手机/Android 版本上使用的 JVM 似乎进行了某种延迟清理。

注意:这是我基于我运行的测试的推断,所以如果有人知道不同,请分享。谢谢!

于 2013-01-22T14:23:37.830 回答