user773737
user773737

Reputation:

Android memory leak between activities

I'm trying to pinpoint this memory leak.

I have two SurfaceViews, A and B. I start A, then navigate to B, then press the back button to go back to A, and then I navigate to B again.

I can see my allocated memory rise each time I do this, and eventually I'll get an out of memory error.

Here is how I navigate to B, from inside the SurfaceView connected to A

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

In both views, I have a lot of Bitmaps drawing. In B, I can't find any references to A, and the only reference outside the context that I can think of is a reference to a Global class that I have. I also have some analytics stuff going on in the background. It could be a million different things, I'd imagine

I have the DDMS view on Eclipse up, but I'm not sure what I'm looking at, or how to find the exact object that keeps getting repeated.

I'd accept either a crash-course/tutorial on the DDMS Allocation Tracker, or someone to point out what I'm doing wrong.


Additional information:

I have some bitmaps being drawn on a SurfaceView. Examples of such from B are:

////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);

And my onDestroys

@Override
public void surfaceDestroyed(SurfaceHolder holder) {


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

So I've run MAT and found one leak, at least. My Thread Keeps getting recreated. Here's what's doing it.

@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);
    }
}

Assuming that these methods get called every time the view loses or gains focus, this seems obviously wrong. How can I re-organize this so that it's not?

Upvotes: 5

Views: 4953

Answers (4)

Payal
Payal

Reputation: 913

Call this method in onDestroy() and onstop() of your app.

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();
        }
 }

Upvotes: 4

Siddharth
Siddharth

Reputation: 9574

What you need to do is explained in detail here. For your specific issue, you need to do this

// 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();

Upvotes: 0

Vincent Mimoun-Prat
Vincent Mimoun-Prat

Reputation: 28541

A few hints:

  • Recycle bitmaps when done with an activity (onDestroy for example)
  • Use the application context rather than the activity itself as context whenever possible

Upvotes: 3

Michał Z.
Michał Z.

Reputation: 4119

Try to recycle() your bitmaps in onDestroy() of your activities.

Upvotes: 1

Related Questions