Friday, July 8, 2011

Figuring out the image memory issue

Ok. So, in the last blog, we found a nice, simple solution to monitoring memory - a free app called, of all things, "Memory Usage". It shows the peak and current usage of an app.

In a simple experiment, I ran 5 consecutive questions which show the "congratulations" image after getting the answer right, and then 5 consecutive questions where the congratulations image did not show. Sur enough, it rose by 1 MB and 2 MB for current and peak respectively on the one the showed the image - and zero if it didn't.

So, clearly the problem lays in how I'm managing those images, especially considering the original error message:

E/AndroidRuntime(15061): Caused by: java.lang.OutOfMemoryError: bitmap
size exceeds VM budget
E/AndroidRuntime(15061): at android.graphics.Bitmap.nativeCreate(Native Method)


So, let's look at this code:

onCreate(....

// Get the image widget
ImageView image = (ImageView) findViewById(R.id.image);

// Set the image
image.setImageResource(imageResourceIds[index]);

image.setOnTouchListener(this);

// set up a timer so the dialog automatically disappears
int totalMsecs = 1 * 50000; // 5 seconds
int callInterval = 1000;

// The countdown timer
new CountDownTimer(totalMsecs, callInterval) {

// required
public void onTick(long millisUntilFinished) {
}

// done
public void onFinish() {
NextLevelActivity.this.finish();
}

}.start();

}

@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
finish();
return false;
}


I don't see the problem though. Ah, wait a second. Didn't that post talk about when you set a drawable (the resource) as attached to a view, the drawable then sets a view as attached to it? But, since they are both going out of scope, why would it make a difference? Is it because of the anonymous inner class?

Hmm, well, he says (Romain Guy in
http://android-developers.blogspot.com/2009/02/track-memory-allocations.html
)

to not create new Paint instance every time, but rather make them an instance variable.

Let's try this first, because I think I understand it. A key think to remember is that if it's an instance variable it only needs to be created once.

I dunno. Let's tak this:

// Get the image widget
ImageView image = (ImageView) findViewById(R.id.image);

and make it a member variable

// Get the image widget
Image = (ImageView) findViewById(R.id.image);

I'm not sure that's the answer - the imageView is just a container for the image.

Rats - I'm not sure that's the problem now. The memory is increasing, even when I don't get into the image handling routine.

I wish I had some kind of profiling tool. I saw an Eclipse plugin.

Memory Analyzer 1.1.0 (Indigo) Release

Install from http://download.eclipse.org/mat/1.1/update-site/

Url is

http://www.eclipse.org/mat/

Ok, open view and Memory Manager. Hmm, the inspector only is on the left panel. Click run.

Wow, it's taking forever - it's it building the memory into the bytecode or something?

Look at top - it's sleeping?

Force quit.

Oh, yeah, this doesn't analyze images, they aren't part of the heap. But, image may or may not be the problem.

Ah, they have a Webinar. It's like a movie. I'll relax and enjoy the presentation, which is probably going to be about an hour.

Hmm...SAP? Does this apply to Android? Yes, but I don't have the patience for it.

Ok, let's go back to the original recommendation - the allocation tracker. Now, I'm seeing my classes in the stack trace. Ok, I'm understanding it better now. You can see the allocated objects.

Now, if I don't show the images, it goes up much more gradually. It's still leaking, though. But slowly. Let's see, we're at 26 25 now. Let's do 10 more.

26 27. Gradually moving up.

What was the maximum?

http://stackoverflow.com/questions/1147172/what-android-tools-and-methods-work-best-to-find-memory-resource-leaks

Most java tools are unfortunately unsuitable for this task, because they only analyze the JVM-Heap. Every Android Application also has a native heap, though, which also has to fit within the ~16 MB limit. It's usually used for bitmap data, for example. So you can run quite easily into Out Of Memory errors even though your JVM-Heap is chillin around 3 MBs, if you use a lot of drawables.


Hmmm...which heap ami I looking at? Anyway, I'm already over 16MB - that's not good.

Well, let's get back to Allocation Tracker.

I'm doing some string building in InitUtils.

It still doesn't help that much - most of the allocations don't trace back to objects I'm familiar with.

Well, let's tackle the image class first. We'll just have to try some of those tricks.

Let's see how fast it grows when we go into the image class again.

Right now it's at 25 / 27 MB.

One show of the image and it's 27 27.

Two and it's at 27 28.

Three and it's still 27 28.

Four - 27 28.

Five - 27, 28.

Seven, it goes to 28, 28.

Ah, here's a pretty good link:

http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html


It looks like this is going to take some time. Again, I will need root access. I need to unlock this phone.

The next post, we'll take a look at unlocking the phone. Then, we'll get back into this whole thing about plugging the memory leak.

That's a wrap for now.

No comments:

Post a Comment