关于(可能的)Android内存泄漏无能为力

时间:2014-05-14 10:51:27

标签: java android memory-leaks bitmap eclipse-memory-analyzer

即使在确保我的所有位图都已正确缩放之后,我也面临着一些烦人的OutOfMemoryErrors。实际上,这个问题似乎与Bitmaps根本没有关系,但我可能是错。

出于测试和错误隔离的目的,我一直在使用导航抽屉(不使用后退按钮)在两个活动之间切换(让我们称之为Main和List)。我可以在DDMS中看到每次返回时分配的内存增加大约180 KB。

我已完成内存转储并使用eclipse MAT分析3个不同的时间点:

Screen1

Screen2

Screen3

我怀疑内存泄漏,但我无法找到原因。根据内存转储,看起来它是“剩余”和java.lang.FinalizerReference不断增加。 this question中的用户在他的内存转储中也有很多FinalizerReferences,但答案并不十分明确。

我在最后一个时间点发布的泄漏嫌疑人报告不是很有帮助,因为它怀疑android.content.res.Resourcesandroid.graphics.Bitmap似乎没有随着时间的推移而增长:

Screen3LeakReport

在其中一份报告中(遗憾的是,此处不存在)我发现有13个android.widget.ListView个实例被指出为潜在的泄密嫌疑人。

这些内存增加发生在活动之间的任何转换(不仅仅是本例中使用的Main和List)。

如何找到(非显而易见的?)内存泄漏?我一直在摸不着头脑,所以任何帮助和提示都会很棒。

编辑:

  • 位图(@ OrhanC1):我在上述两项活动中评论过任何Bitmap实例,内存仍在增加。内存转储仍显示一些位图,但我相信它们与资源有关,而不是我分配的实际位图。

  • 关于自定义字体(@erakitin):我正在使用它们,但我在Typeface上下文中保留每个Application的单个实例({{ 1}})使用单身人士。我已尝试评论上述两项活动中对字体的任何引用,内存仍在增加。

  • 我认为我没有泄漏public class MyApp extends Application(@DigCamara):我不会在这两项活动中保留任何静态参考资料,我是除了适配器之外,使用Context上下文而不是Application' s。如果我保持相同的Activity并进行一些屏幕旋转,则内存不会增加。

  • 基于@ NickT的评论:我可以看到我有两个活动的很多实例。这些内存增加是否只是后台堆栈活动数量增加而不是内存泄漏的结果(我虽然操作系统处理了这个,apparently not)?如果我使用Activity意图标志,那么内存只会增加,直到所有不同的活动都被实例化(一次)。这个问题很有用:Android not killing activities from stack when memory is low

1 个答案:

答案 0 :(得分:11)

看起来Remainder正在增长的原因是后台堆栈中Activity个实例数量的增长(例如“列表”{13}的13个实例+ 13 “Main”Activity)的实例。

我已经改变了我的导航抽屉,以便当用户点击“主页”按钮(将他带到应用程序的“仪表板”)时,我设置了Activity标志:重新使用活动并且后台堆栈被清除(as recommended by the Android guidelines, actually)。事实上,我应该已经这样做了,因为我不想创建仪表板(“Home”)活动的几个实例。

通过这样做,我可以看到活动被破坏,分配的堆大小(包括“Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK”切片)减少了:

Fixing problem with increasing memory.

在修复此问题时,我还注意到我的一个Activity和它使用的Bitmap没有被破坏,即使后备堆已被清除(泄漏)。在用MAT分析之后,我得出结论,这个子问题的来源是我在Remaining中保留的ImageView的引用。通过将此代码添加到Activity方法,我设法将活动和onStop()都销毁:

Bitmap

然后我概括了所有@Override protected void onStop() { super.onStop(); ImageView myImage = (ImageView) findViewById(R.id.myImage ); if(myImage .getDrawable() != null) myImage.getDrawable().setCallback(null); RoundedImageView roundImage = (RoundedImageView) findViewById(R.id.roundImage); // a custom View if(roundImage.getDrawable() != null) roundImage.getDrawable().setCallback(null); } Activity,以便他们在FragmentActivity中致电unbindDrawables(View view)

onDestroy()

感谢@NickT指出我正确的方向。