4

I'm writing a program that involves a ton of images, over 100 per screen density. Fortunately, they aren't very big in terms of space. I use roughly 11 at any given time. I also use the function Bitmap.createScaledBitmap on every image which seems to take up a lot of memory.

So far in debugging this app, I seem to be able to use it indefinitely without running into a memory problem, which I'm hoping means I'm not leaking memory.

However, the one thing I've noticed is that if I "exit" my app through the back button (I'm not running anything in the background), and then restart the app shortly after, I sometimes get a out of memory error at a call to Bitmap.createScaledBitmap

01-07 19:01:24.935: ERROR/AndroidRuntime(27419): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

So basically my question is, what am I doing wrong here? Do I need to be cleaning up my own garbage, like in onDestroy when the user presses the back button? I would have thought the GC would automatically take care of this when the back button was pressed and the activity was destroyed. This leads me to believe I am doing something else wrong, like a memory leak. But then I come back to the fact my app can take heavy memory use for 20 minutes but then kill itself in 5 seconds after a restart, which is what is baffling me.

Thanks all.

Edit: I implemented a couple quick and dirty fixes.

First I tried this, and it was harder to get the application to force close.

@Override
public void onBackPressed() {
    finish();
}

Next I tried this combined with the onBackPressed and I could no longer duplicate my problem. Note that the method call is just a loop that basically does allImages = null;

protected void onStop () {
    super.onStop();
    mComponent.releaseImages();
}

At this point it appears that after calling finish(), there are still objects in memory from the activity. Rather strange.

user432209
  • 20,007
  • 10
  • 56
  • 75
  • The dirty little quick fixes are only a short solution for your specific problem. I'd rather solve this sort of problems using the pattern I mentioned in my answer. – Wroclai Jan 08 '11 at 01:42

3 Answers3

3

Maybe you got something about the android lifetime of your application wrong. Pressing the back button does not kill your java program. SO sarting your app again does start a new app.

See http://developer.android.com/guide/topics/fundamentals.html#actlife

If you for example create the images in onStart() but do not remove them in onStop() you still have the references to your images. Each time will add more memory.

plaisthos
  • 6,255
  • 6
  • 35
  • 63
  • My understanding is pressing the back button does indeed do a finish() unless you have chosen to override that method to perform different operations. In my case, I am not overriding anything thus a finish should get called. Think of my app as a single activity app if it helps you visualize it. – user432209 Jan 08 '11 at 00:45
  • From my understanding pressing the back button and starting the app immeadtly again will go through onStop(), onRestart(), onStart(). The finish() is a call you call yourself if your Activity is done. It is important to remember that closing/exiting an android application does not necessarly kill the java process. It will be resumed when the application is started again. – plaisthos Jan 08 '11 at 00:51
  • I wish that was documented better. – user432209 Jan 08 '11 at 02:15
2

1: When your application is resumed by onResume() your previous Bitmap objects are loaded once again. You need to make sure you don't allocate all Bitmap objects one more time.

2: It's very often it's memory leaks that causing these errors. The Bitmap objects still have references to their initializon state when your application is resumed. You can use a specific pattern to prevent reallocating same Bitmap objects. This pattern is called Memory Pools and it prevents fragmentation of your memory.

Think of fragmentation like this: You're trying to park a car. A stupid human parked a little too much to right and another stupid human parked a little too much to left. That slot is fragmented. Originally you should have enough of space to park your car right in that spot but the parking area itself is now fragmented. There's no empty slot for your car - the parking area is running out of memory.

To prevent that scenario, you can use the Memory Pools pattern.

By using this pattern you can:

  • Set a total maximum of Bitmap objects you will use during the application's lifetime.
  • Ask for an empty slot when your application is resumed and then reinitialize your Bitmap objects instead of reallocate them.

By using this pattern you need to make sure:

  • That you have enough space for your Bitmap objects in the specific pool.

However, the solution of part two isn't necessary at all (hey, it's a good tool).

The short solution: You can't create same amount of Bitmap objects when the application is resumed when you still have old Bitmap references in memory. Check if you already have your Bitmap objects loaded when your application is resumed and if you don't, create them.

Wroclai
  • 26,835
  • 7
  • 76
  • 67
  • Charlie Sheen wrote "Check if you already have your Bitmap objects loaded when your application is resumed and if you don't, create them." --- This is probably the best answer and what I should do, but my band-aid posted above seems to have worked. – user432209 Jan 08 '11 at 01:39
-1

This problem has been attributed to a bug with android. Refer to the following links for information about the problem and some workarounds.

OutofMemoryError: bitmap size exceeds VM budget (Android)

http://code.google.com/p/android/issues/detail?id=8488

http://mobi-solutions.blogspot.com/2010/08/how-to-if-you-want-to-create-and.html

Community
  • 1
  • 1
user432209
  • 20,007
  • 10
  • 56
  • 75