调用finish()不会清除对Activity的内存引用

时间:2013-01-21 18:48:47

标签: android memory-leaks back-stack android-memory mat

在我的应用程序的简化版本中,我有两个活动,A和B. Actvity A启动B,在一些工作之后B调用finish()。在大多数设备上使用Memory Analyzer工具(运行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 个答案:

答案 0 :(得分:2)

更新:为了查看活动B留下的“搁浅”内存是否实际上是一个问题,我在活动A和B之间创建了一个循环:

--- A calls startActivityForResult() on B
--- B calls finish()
--- onActivityResult() in A calls B again, etc...

我让它飞行大约15k迭代,程序没有崩溃。所以即使这款手机上的JVM和操作系统版本(三星S3,4.1.1)在内存中留下了对B类的引用,即使在活动B调用finish()之后,它也会出现稍后的清理,如同在测试期间,B类的参考数量没有单调增加。

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

我的结论是,我不应该担心在finish()调用之后堆转储中存在B类引用,因为看起来这个手机/ Android版本上使用的JVM会进行某种延迟清理。 / p>

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