Android活动之间的内存泄漏

5

我正在尝试定位这个内存泄漏。

我有两个SurfaceViews,A和B。我先启动A,然后导航到B,然后按返回按钮回到A,再导航到B。

每次这样做时,我都可以看到我的分配内存增加,最终会收到内存不足错误。

以下是我从与A连接的SurfaceView内部导航到B的方法:

        Context context =  this.getContext();
        Intent i =new Intent(context, StartCareer.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(i);

在两种情况下,我都有很多位图绘制。在“B”中,我找不到任何与“A”相关的引用,唯一的引用是指向我拥有的全局类的上下文之外的引用。我还有一些后台分析工作正在进行。我想这可能是无数不同的因素。
我在Eclipse上使用了DDMS视图,但我不确定我在看什么,也不知道如何找到重复出现的确切对象。
我愿意接受DDMS分配跟踪器的速成课程/教程,或者有人指出我做错了什么。
额外信息:
我有一些位图在SurfaceView上绘制。例如来自“B”的:
////At class level
Bitmap rightB,leftB;
////In the constructor
rightB = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.right), 100,75, true);
////In doDraw
canvas.drawBitmap(rightB, rbX, rbY, null);

我的onDestroy方法

@Override
public void surfaceDestroyed(SurfaceHolder holder) {


    if (mThread.isAlive()){
        mThread.setMenuRunning(false);
    }
}

我运行了MAT并找到了至少一个内存泄漏。我的Thread不断被重新创建,以下是其原因。

@Override
public void surfaceCreated(SurfaceHolder holder) {
    loading=false;
    if (!mThread.isAlive()){
        mThread = new ViewThread(this);
        mThread.setMenuRunning(true);
        mThread.start();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

    if (mThread.isAlive()){ 
        mThread.setMenuRunning(false);
    }
}

假设这些方法每次视图失去或获得焦点时都会被调用,这显然是不正确的。我该如何重新组织以避免这种情况?

这些活动上有位图吗? - Siddharth
在与它们相关的SurfaceViews中,是的。 - user773737
1
粘贴那段代码,然后加上你的onDestroys。 - Siddharth
这个 Global 类是做什么的?它是否持有任何视图、可绘制对象、处理程序或类似的引用?静态变量呢?有许多常用的对象会在内存中保留整个 Activity 上下文。 - mkuech
我在我的第一块代码下面确实提到了“位图” - user773737
显示剩余4条评论
4个回答

4

在你的应用程序的onDestroy()onStop()方法中调用此方法。

private void unbindDrawables(View view) {
     Log.d(TAG,"in unbindDrawables");
        if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
        ((ViewGroup) view).removeAllViews();
        view.setBackgroundResource(0);
        Log.d(TAG,"removed views");
        //finish();
        }
 }

我将这个添加到了 B 中,但它从未到达第二个 Log 语句。 - user773737
请您能否添加一些关于代码的解释。 - seenukarthi

3

一些提示:

  • 当活动结束时(例如,在 onDestroy 中),请回收位图
  • 尽可能使用应用程序上下文而不是活动本身作为上下文

1
尝试在活动的onDestroy()中回收位图。

我会尝试这样做,但是就我目前的了解,我不知道如何访问我创建的视图的成员。 - user773737
你可以在创建Bitmap对象后调用recycle()方法,例如:Bitmap rightB,leftB; 然后使用rightB.recycle(); - Michał Z.
好的,我尝试回收我在B中绘制的所有三个位图,但似乎没有帮助。内存泄漏仍然发生。问题必须出现在其他地方。 - user773737
1
所以,我实现了这个功能,但每当我退出应用程序并重新进入时,它就会崩溃,因为我尝试绘制的位图已被回收。可能是因为该位图是静态的。 - user773737
静态的非平凡成员已知会泄漏上下文。我会从那里开始调查。 - Makibo

0
你需要做的是在这里详细解释。针对你的具体问题,你需要这样做


// resize to desired dimensions
    int height = b.getHeight();
    int width = b.getWidth();
    Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
       height: " + height);

    double y = Math.sqrt(IMAGE_MAX_SIZE
            / (((double) width) / height));
    double x = (y / height) * width;

    Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, 
       (int) y, true);
    b.recycle();

我遇到了内存泄漏问题。我没有向位图分配太多内存。 - user773737
无论您分配了多少内存,清理工作都是必不可少的。Bitmap 在相对较小的内存量下就能很快导致 OOM。 - Siddharth

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