1

In my Fragment I have a custom view that extends LinearLayout. Let's call it gallery

In that custom view I have 5 ImageView. Each contains an image loaded from web.

When my Fragment is no longer required I destroy references in onDestroyView()

@Override
public void onDestroyView() {
    super.onDestroyView();
    gallery = null;
}

I noticed, that my app leaks memory and using DDMS and MAT I found that those 5 Bitmap in those ImageViews are still in memory. Well that's no good. So on the next step I did this in my mini gallery

@Override
protected void onDetachedFromWindow() {
    super.onDestroyView();
    imageView1 = null;
    ...
    imageView5 = null;
}

That didn't help either. On my last attempt I did this

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    imageView1.setImageBitmap(null);
    imageView1 = null;
    ...
    imageView5.setImageBitmap(null);
    imageView5 = null;
}

That helped. Memory was freed and memory leaks were plugged up.

Now my question is - why? Why, when my gallery was not referenced by anything it was not GC'ed? And even more - when ImageView was not references it's content - Bitmap - was never GC'ed? Should I forcefully clean image bitmap?

I noticed that in other custom views where ImageView is used I had a similar problem. What are best practices for such cases?

Martynas Jurkus
  • 9,231
  • 13
  • 59
  • 101
  • How are you destroying that `View`? I mean, what do you call/do to make sure your `onDestroyView()` method is being called? – nKn Feb 19 '14 at 20:53
  • It is a part of Fragment lifecycle. – Martynas Jurkus Feb 19 '14 at 21:12
  • That's right, what I mean is that `onDestroyView()` is only called when the `finish()` method is called. That **doesn't guarantee your `onDestroyView()` will be called** and probably there's where the leak is coming from. By the way, in your `onDetachFromWindow()` method you just call `super.onDestroyView()`, you wouldn't be calling your custom implementation. You might want to have a look at this http://stackoverflow.com/questions/6117341/why-implement-ondestroy-if-it-is-not-guaranteed-to-be-called – nKn Feb 19 '14 at 21:21

2 Answers2

2

As we all know that the its uncertain when GC is called and as @Farhan rightly said calling system.gc() too doesn't guarantee that objects will be garbage collected, we cannot really rely upon it. Also its not recommended to do the cleanup thyself.

So, finding solution to this issue particularly for Bitmaps I landed up to this function from the Bitmap class, which says

public void recycle ()

Added in API level 1 Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. The bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.

Even tough it is said that it should not be called. The important lines about it noticed are Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. which states that calling this method will make the bitmap garbage collected.

Searching more on this I found a long discussion on the same issue faced by many, here.

And amongst the discussion the I found a solution posted by Sandeep Choudhary, who gives a small workaround with details using Bitmap.recycle() here.

Atul O Holic
  • 6,692
  • 4
  • 39
  • 74
0

GC will be get called when there is a need. like os was running low on memory, then it will call gc.. and gc will then check all unreferenced objects and clear them.

You only need to make sure, you are not keeping the reference unnecessarily.

Farhan
  • 13,290
  • 2
  • 33
  • 59
  • Well I received OOM errors because of this custom view... And I'd say it's true when I removed reference to `gallery` in my fragment. But when I removed references to every single `ImageView`... And I had 30 ImageViews in memory after 6 fragment visits. And forcing GC via DDMS did nothing. – Martynas Jurkus Feb 10 '14 at 13:41
  • calling system.gc() also not force it to call, its just a notifier to the system that "This may be the right time to call gc".. something like that.. – Farhan Feb 10 '14 at 13:48
  • how you making the bitmap? you might want to share little more code regarding that custom view. – Farhan Feb 10 '14 at 13:49
  • There is nothing special with my custom view. It acts as a container for image views and extracted to separate view for reusability. Bitmaps are created by `UniversalImageLoader` library. – Martynas Jurkus Feb 10 '14 at 14:02