Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对(可能的)Android内存泄漏一无所知_Java_Android_Memory Leaks_Bitmap_Eclipse Memory Analyzer - Fatal编程技术网

Java 对(可能的)Android内存泄漏一无所知

Java 对(可能的)Android内存泄漏一无所知,java,android,memory-leaks,bitmap,eclipse-memory-analyzer,Java,Android,Memory Leaks,Bitmap,Eclipse Memory Analyzer,我一直面临一些恼人的outofmemory错误,即使在确保所有位图都正确缩放后也是如此。事实上,这个问题似乎根本与位图无关,但我可能错了 出于测试和错误隔离的目的,我一直在使用导航抽屉(而不是使用后退按钮)在两个活动(让我们称之为Main和List)之间切换。我可以在DDMS中看到,每次返回时,分配的内存都会增加大约180 KB 我进行了内存转储,并使用eclipse MAT分析了3个不同的时间点: 我怀疑内存泄漏,但我不能真正找出它的原因。根据内存转储,看起来是“余数”和java.lan

我一直面临一些恼人的
outofmemory错误
,即使在确保所有位图都正确缩放后也是如此。事实上,这个问题似乎根本与位图无关,但我可能错了

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

我进行了内存转储,并使用eclipse MAT分析了3个不同的时间点:

我怀疑内存泄漏,但我不能真正找出它的原因。根据内存转储,看起来是“余数”和
java.lang.FinalizerReference
不断增加。中的用户在内存转储中也有很多
finalizerreference
,但答案并不十分清楚

我在上一个时间点所做的泄漏嫌疑报告没有太大帮助,因为它怀疑
android.content.res.Resources
android.graphics.Bitmap
似乎不会随时间增长:

在其中一份报告中(遗憾的是,这里没有出现),我看到了13个
android.widget.ListView的实例被认为是潜在的泄漏嫌疑犯

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

如何找到(不明显的?)内存泄漏?我已经挠头很久了,所以任何帮助和提示都会很好

编辑:
  • 位图(@OrhanC1):我已经对上面提到的两个活动中的任何
    Bitmap
    实例化进行了注释,内存仍然在增加。内存转储仍然显示一些位图,但我相信它们与资源相关,而不是我分配的实际位图

  • 关于自定义字体(@erakitin):我正在使用它们,但是我在我的
    应用程序
    上下文(
    公共类MyApp扩展应用程序
    )中使用了一个单例来保存每个
    字体
    )。我试着在上面提到的两个活动中对字体的任何引用进行注释,但内存仍然在增加

  • 我不认为我泄露了
    上下文
    (@DigCamara):我在这两个活动中没有任何静态引用,我使用的是
    应用程序
    上下文,而不是
    活动
    ,适配器除外。如果我保持在相同的
    活动中,并进行一些屏幕旋转,内存不会增加

  • 根据@NickT的评论:我可以看到这两种活动都有很多实例。这些内存的增加是否仅仅是后堆栈活动数量增加的结果,而不是内存泄漏(我认为操作系统已经解决了这一问题)?如果我使用
    标志\u ACTIVITY\u REORDER\u TO \u FRONT
    intent标志,那么内存只会增加,直到所有不同的活动都被实例化(一次)。对这件事有用:


看来
余数
增长的原因是后堆栈中
活动
实例数量的增长(例如,“列表”
活动的13个实例
+13个“主”
活动

我已经更改了导航抽屉,因此当用户单击“主页”按钮(将他带到应用程序的“仪表板”)时,我将
Intent.FLAG\u ACTIVITY\u REORDER\u设置为\u FRONT | Intent.FLAG\u ACTIVITY\u CLEAR\u TOP | Intent.FLAG\u ACTIVITY\u NEW\u TASK
标志:活动被重新使用,后堆栈被清除()。事实上,我应该已经这样做了,因为我不想创建多个Dashboard(“主页”)活动实例

通过这样做,我可以看到活动被销毁,分配的堆大小(包括“
剩余的
”切片)减小:

在修复此问题时,我还注意到我的一个活动及其使用的位图没有被破坏,即使后堆栈已被清除(泄漏)。在使用MAT进行分析后,我得出结论,该子问题的根源是我在
活动中保存的
图像视图
。通过将此代码添加到
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);


}
然后,我概括了我所有的
活动
片段活动
,以便它们在
ondestory()中调用
unbindDrawables(视图)

private void unbindDrawable(视图)
{
if(view.getBackground()!=null)
{
view.getBackground().setCallback(null);
}
if(查看视图组的实例&!(查看AdapterView的实例))
{
对于(int i=0;i<((视图组)视图)。getChildCount();i++)
{
未绑定的Drawables(((视图组)视图).getChildAt(i));
}
((视图组)视图);
}
}

感谢@NickT为我指明了正确的方向。

您是否在每次转换中都会启动活动的新版本(而不是重用后台实例)?也许我对此的回答很有用:当你完全删除位图时会发生什么?没有看到你的代码,我们只能猜测发生了什么。@Squonk-我同意你的观点,但在这种特殊情况下很复杂:因为我真的不知道问题的根源,我不得不发布大量的代码。@OrhanC1-我已经对任何问题进行了注释在两个示例活动中创建位图。记忆仍在增长。
private void unbindDrawables(View view)
{
    if (view.getBackground() != null)
    {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup && !(view instanceof AdapterView))
    {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
        {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}