Android应用程序的内存堆不断增长

7
我一直在我的应用程序中遇到随机的(内存不足)崩溃,所以我开始分析我的堆。我注意到,如果我从Activity A转到Activity B,由于懒加载许多图像,堆会从27 MB增加到35 MB。然而,当我使用finish()函数从Activity B返回到Activity A时,尽管进行了GC操作,堆大小仍保持不变!
令人烦恼的是,再次转到Activity B会将堆增加到42 MB。我可以这样做很多次,但堆只会不断增加。
这是我正在使用的懒加载图片库:
LazyList https://github.com/thest1/LazyList 这些是堆的截图:
before: http://i.stack.imgur.com/7eTzm.png after: http://i.stack.imgur.com/txeC6.png 可根据要求提供转换后的堆转储文件
更新:

从我的调试情况来看,似乎问题出在LazyList库中,但我仍不确定百分之百。这里有人对该库进行评论:

https://github.com/thest1/LazyList/issues/20


听起来你的活动正在泄漏一些数据。你有任何IPC成员变量或其他可以在没有活动的情况下继续运行的东西吗? - Zach Rattner
没有进程间通信(IPC) 为了在没有活动的情况下继续,我正在使用的库使用多个线程(可以在没有活动的情况下运行)。 - AlAsiri
如果您已经解决了这个问题,请反馈一下。期待您的回复。 - kamal_tech_view
3个回答

1
我的猜测是您正在泄漏活动(这可能会泄漏它所持有的所有变量)。确保注销了需要传递上下文的任何操作系统调用,没有任何对象通过保留上下文而持有对活动的引用(尤其是通过保留上下文持有对活动的引用),并且在onDestroy或onStop中将您可以清空的所有内容都设置为null(并在所有重要对象中执行此操作)。
如果这还不够,请查看您的hprof,查看在您杀死活动后存在哪些大型对象以及谁持有引用。修复并重复。

如何取消注册需要传递上下文的操作系统调用? 你能给我展示个例子吗? - AlAsiri
你在哪里使用上下文?如果它在监听器内部,你可能需要将其删除。但一般来说,我认为没有必要保留从Activity A到Activity B的引用。 - dmon
我同意这个观点。但是将Context对象传递给监听器或数据对象并将其存储为成员变量并不罕见,如果您不将其置空,则会泄漏。甚至常见的情况是稍后决定将这些变量作为单例或全局变量,而没有考虑到上下文变量(可能已经被传递到其他对象的构造函数中,该对象执行此操作,但您只是保留了原始对象)。这样做的常见原因是访问诸如SharedPreferences或XXXManager类之类的内容。 - Gabe Sechan
@dmon,我该如何在监听器中清除上下文? - AlAsiri
找到了,原来是我分配的一堆对象,在退出活动时系统没有释放它们。因此,我必须手动释放它们,通过删除它们来实现。 谢谢大家的帮助!! - AlAsiri
显示剩余3条评论

1
我觉得你每次都在启动一个新的活动,而不是切换到已经加载的活动。尝试在切换活动时设置意图标志以包括 Intent.FLAG_ACTIVITY_REORDER_TO_FRONT

看这里


我认为这不是问题,因为已经打开的活动应该通过GC清理干净,原因是由于存在内存泄漏,其中某些引用持有活动引用,且活动实例无法清除。 - kamal_tech_view

0

在我看来,可能是你使用的图像有问题。Android中的BitmapFactory创建不可变的位图,对这些位图所做的任何更改都将与原始图像分开。

更糟糕的是,即使你告诉它回收(recycle),它也会依赖于你的引用,以确定是否会被垃圾回收。


我也这么认为。你认为使用SoftReference可以解决这个问题吗? - AlAsiri
我更倾向于使用此处提供的建议:http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html。这个:http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html似乎特别相关。 - DigCamara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接