1

I'm experiencing a bunch of wacky (and very hard to find) memory leakage in my Android app. I don't have any static Bitmaps (which is what all the tutorials regarding leaking Bitamps tell you not to do). I do however, have a Bitmap that I'm storing in my Application class which is being used by a bunch of my activities. I AM calling recycle() on that when the last activity exits, but I'm wondering if it would be safer to just store the data as a byte[] and create a Bitamp out of it locally in each Activity that uses it, and then release it as soon as it's done. I'm curious of byte[] is construct that the VM has an easier time garbage collecting than the Bitmap (which it seems to totally suck at).

All help GREATLY appreciated.

Adrian
  • 5,603
  • 8
  • 53
  • 85
Yevgeny Simkin
  • 27,946
  • 39
  • 137
  • 236
  • Where does your data come from? Is it network? Why do you need to store it in memory? – aromero Jan 25 '12 at 21:29
  • aromero, the data comes from the camera and image resources. I'm using stock images and superimposing carved portions of photos people take of themselves. So, I have no choice but to read, and handle, both elements in memory. – Yevgeny Simkin Jan 25 '12 at 23:34

3 Answers3

1

Changing from a Bitmap to a byte[] isn't going to solve the problem, which is caused by maintaining a reference to the Bitmap object. Instead of calling recycle(), you should set the reference to null when the last activity exits. That will do everything that calling recycle() does plus allows the GC to harvest the Bitmap object itself. (The GC doesn't distinguish between Bitmap and byte[] when it comes to recycling. An unreferenced object is an unreferenced object...)

The only other thing to suggest (if the Bitmap really is the source of your memory leak) is to use a WeakReference<Bitmap> in your application class instead of a hard reference. Then each activity can get() the actual Bitmap (if it's still there). Then you don't have to set it to null; the GC will automatically harvest the Bitmap when there are no hard references, leaving behind an empty weak reference.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • that's VERY interesting! and of course I'm the kind of idiot that didn't bother setting my references to null, thinking that recycle() handles that for me (why would it... it only SOUNDS like it absolutely should! :)... thanks very much, I'll give all this a whirl. – Yevgeny Simkin Jan 25 '12 at 23:32
  • 1
    I think that calling recycle() will take care of most of the memory a bitmap holds, since bitmaps are handled natively. So nulling the reference won't make much difference (versus calling recycle(), specially if we are talking about only one object). – aromero Jan 25 '12 at 23:54
  • @aromero - Exactly. That's why I expressed some doubt that this one Bitmap is the source of the memory leak. – Ted Hopp Jan 26 '12 at 00:10
  • well... the thing is that the app runs fine several times through, and then crashes, out of memory. So, I'm definitely not releasing *something, but I'm stumped as to what. There are two things it uses. Some fairly large PNGs (that are the backgrounds) and image data from the front facing camera, which I store in my Application since the photo taking Activity is not the same as the compositing one. As soon as I don't need the user's photo, I call recycle() on it, and on everything else I'm using, so, I'm hunting for the leak... thanks for your help. – Yevgeny Simkin Jan 26 '12 at 00:53
0

I know this question has already been answered, but just as a side note: When dealing with Bitamps, it's one of those things that Android handles natively (ie through C code, not Java code). So even if you release all references to it, it'll still be stored in memory on the native side and count against your app.

StackOverflowed
  • 5,854
  • 9
  • 55
  • 119
0

If you are dealing with bitmaps taken from the camera you need to be very careful with the size of the images.

A picture taken with the camera can be pretty big. When you open the image as a bitmap, you are loading the full array into memory. Consider the Nexus One with a 5MP camera. User pictures taken with the device can be as big as 2048x1536. Using 24 bits pixel depth, we are talking about nearly 9MB. This is huge if take into account the 16/24 MB heap limit.

Solution is to work with a smaller size, usually you won't need the full sized image since the device will have a much lower resolution, plus the size of your ImageView (or any other surface you use to display the bitmap) won't usually take all the screen.

BitmapFactory.decodeByteArray(...) (and other factory methods) can take a BitmapFactory.Options object where you can specify a scale factor through inSampleSize. This doesn't affect the original data, so you can keep your full size image and get a sampled bitmap in memory. You can combine this by previously using inJustDecodeBounds = true to read the size of the image, then calculate the scale factor based on the size of the image and the size of your viewport and finally obtain the scaled bitmap.

This question might be handy (not the chosen answer, but the other two with high score): Strange out of memory issue while loading an image to a Bitmap object

Edit: oops, posted wrong link to question

Community
  • 1
  • 1
aromero
  • 25,681
  • 6
  • 57
  • 79