5

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?

  • Do you have bitmaps on these activities ? – Siddharth Jan 31 '13 at 07:33
  • In the `SurfaceViews` associated with them, yes. –  Jan 31 '13 at 07:35
  • 1
    Paste that code, and your onDestroys – Siddharth Jan 31 '13 at 07:35
  • What does this Global class do? Does it hold any references to any Views, Drawables, Handlers, or anything like that? What about from static variables? There are a number of commonly used objects that keep an entire Activity context in memory. – mkuech Jan 31 '13 at 07:42
  • @Siddharth done @mkuech The Global class holds various ints, strings, oh, and a `Resources`, which is set from the constructor of `A` –  Jan 31 '13 at 07:45
  • See, as soon as you said bitmaps you got a bunch of answers. – Siddharth Jan 31 '13 at 07:49
  • Well, I did mention "bitmaps" right under my first block of code –  Jan 31 '13 at 07:50
  • I updated my question with a known memory leak. –  Feb 03 '13 at 21:58
  • Now I narrowed down my memory leak, and it is its own question: http://stackoverflow.com/questions/14677913/how-do-i-fix-this-android-memory-leak-involving-threads –  Feb 04 '13 at 20:07

5 Answers5

5

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();
        }
 }
Karthikeyan
  • 7,700
  • 10
  • 46
  • 66
Payal
  • 913
  • 1
  • 9
  • 27
3

Use DDMS to create heap dump (*.hprof file), button near "heap enable".

Then convert this file to another *.hprof using standart sdk tool "hprof-conv.exe"

Then download eclipse memory analyzer tool (http://www.eclipse.org/mat/) (i've downloaded it as standalone tool), and open your new *.hprof file, it has "memory leak analyzer" and can tell you where probably you have mistakes (it said that bufferObjectManager is too huge and took over 50% of overall memory).

When i clean it (BufferObjectManager.getActiveInstance().unloadBufferObject(((RectangularShape) obj).getVertexBuffer());) it helps a little but still there is a problem.

If you completly clear this buffer you'll loose your texture etc. If the problem is only in memory leak while closing the app the way to avoid this problem is clear (onDestroy();) this buffer.

jlopez
  • 6,287
  • 2
  • 51
  • 90
  • I downloaded this, and ran the leak analyzer, and it's giving me a nice little pie chart that doesn't really tell me anything. Probably because I don't know how to use this yet –  Jan 31 '13 at 08:06
  • Also, it looks like you copy-pasted this answer from somewhere else. What's all this about a vertex buffer? –  Feb 03 '13 at 20:43
  • Well, you helped me narrow it down, at least, which was the most help. –  Feb 03 '13 at 22:05
  • My found memory leak is now it's own question: http://stackoverflow.com/questions/14677913/how-do-i-fix-this-android-memory-leak-involving-threads –  Feb 04 '13 at 20:05
3

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
Vincent Mimoun-Prat
  • 27,630
  • 15
  • 77
  • 123
1

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

Michał Z.
  • 4,099
  • 1
  • 21
  • 32
  • I'll try this, but off the top of my head, I don't know how to access members of the view I created –  Feb 03 '13 at 20:16
  • You call recycle() on Bitmap objects you created like: Bitmap rightB,leftB; it would be like rightB.recycle(); – Michał Z. Feb 03 '13 at 20:19
  • Well, I tried recycling all three of the bitmaps I draw in `B`, but it doesn't seem to help. The memory leak still occurs. The problem must be elsewhere –  Feb 03 '13 at 20:32
  • 1
    So, I implemented this, and whenever I exit out of my app, and come back in, it crashes since the bitmaps that I'm trying to draw are recycled. Maybe because the bitmap is static. –  Feb 09 '13 at 23:21
  • Static non-trivial members are known to leak context. I would begin the investigation there – Makibo Jul 03 '13 at 23:19
0

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();
Community
  • 1
  • 1
Siddharth
  • 9,153
  • 15
  • 80
  • 142
  • I'm having memory leaks. I'm not allocating too much memory toward bitmaps –  Feb 03 '13 at 20:46
  • Regardless of how much memory you are allocating, cleanup is essential. And Bitmaps are known to cause OOM very quickly with relatively small amounts of memory. – Siddharth Feb 04 '13 at 02:36