Bitmap, Bitmap.Recycle(), Weakreferences, and Garbage Collection

Bitmap, Bitmap.recycle(), WeakReferences, and Garbage Collection

Bitmap.recycle isn't required to be called, as the garbage collector will clean up bitmaps on its own eventually (as long as there are no references). Bitmaps in Android are created in native memory, not on the VM heap, so the actual bitmap object on the VM heap is very small as it doesn't contain any actual bitmap data. (EDIT: no longer the case as of Android 3.0+) The real size of the bitmap will still be counted against your heap usage for purposes of GC and making sure your app doesn't use too much memory.

However, the GC seems to be a little moody when it comes to Bitmaps. If you just remove all hard references, it would sometimes (in my case) hang onto the Bitmaps for a little while longer, perhaps because of the weird way Bitmap objects are allocated/counted. Bitmap.recycle seems to be good for getting the GC to collect that object more quickly.

Either way, you won't leak memory if you don't call Bitmap.recycle as long as you don't keep hard references accidentally. You may encounter OutOfMemoryErrors if you try to allocate too many bitmaps at once or too large bitmaps without calling recycle, though.

EDIT: It is important to note that as of Android 3.0, Bitmaps are no longer allocated in native memory. The are allocated on the VM heap like any other Java object. However, what I said about not needing to call recycle still applies.

Should I trust the Garbage Collector after calling Bitmap.recycle()?

Question 1: Can I just trust that the garbage collector will take that memory back if needed?

Yes. If the incoming references are cleared, the garbage collector will take the memory when it is needed (typically for a new allocation). Calling recycle() doesn't help this process along or make it happen any faster.

The recycle() method exists because Bitmap objects were not counted against the heap until Android 3.0; so the method was helpful to assist the GC since it didn't otherwise have a record of that memory counted against its heap. In 3.0+, the memory is tracked against the heap so this extra bookkeeping isn't necessary anymore.

Question 2: When using Bitmap creation methods, that may or may not return the same bitmap or a copy, do I need to check source and output equality to recycle the source if it's a copy?

The createBitmap() method will return the same object if:

  • The source is immutable
  • x and y are both zero
  • width and height match the source width and height
  • No transformation matrices have been applied

Since it looks like you are passing in a transformation matrix, you will always get a copy unless the matrix is identity for some reason. But again, no real need to recycle() unless you are still supporting 2.x versions.

Recycle the Bitmap of a BitmapShader

After some research I've found that the bitmap must still be recycled, as the BitmapShader doesn't perform any release on it.

The way to proceed is to ensure the BitmapShader is no longer used at all by any other class. So, if for example the BitmapShader is used by a Paint instace, such as paint.setShader(bitmapShader), then before recycling the bitmap, remove the shader reference like paint.setShader(null).

Once ensured the BitmapShader isn't used and is not going to be reused at all, then recycle the bitmap as usual.

When (if at all) should I use Bitmap.recycle()?

in what situations should I use this method?

The Bitmaps are GC'ed by GC whenever it decides.But in some situations it may get delayed.
And always remember thumb rule in java (Maybe it applies to othe P.L also).The speed of recycling objects by GC may not be same as speed of creating objects.So sometimes the GC is slow to in recycling.

so recycle() means If you want to free memory ASAP you should call recycle()

should I use this method at all??

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.But if you are facing the issues like bitmap size exceeded vm budget or out of memory error then you need to use this.

Is it a good idea to call recycle() and destroyDrawingCache() after creating a bitmap, performance-wise?

Quoting from the docs

http://developer.android.com/training/displaying-bitmaps/manage-memory.html

On Android 2.3.3 (API level 10) and lower, using recycle() is recommended. If you're displaying large amounts of bitmap data in your app, you're likely to run into OutOfMemoryError errors. The recycle() method allows an app to reclaim memory as soon as possible.

Android 3.0 (API Level 11) introduces the BitmapFactory.Options.inBitmap field. If this option is set, decode methods that take the Options object will attempt to reuse an existing bitmap when loading content. This means that the bitmap's memory is reused, resulting in improved performance, and removing both memory allocation and de-allocation.
In honeycomb and later versions bitmap pixel data is allocated on the heap. So you don't need to call recycle in this case. When gc kicks in it will free the memory allocated for bitmaps.

Its the job of the garbage collector to free memory. When it needs to reclaim memory garbage collector kicks in. GC deos mark and sweep. You can check the logcat.

You can see the pause times. Large the heap more frequently gc kicks in and more frequent pause times.

 GC_CONCURRENT freed <1K, 14% free 21220K/24455K, paused 6ms+26ms
GC_CONCURRENT : Jumps in because Heap is full
14% free 21220K/24455K After this collection 14% of memory is free. Check the heap usage.
paused 6ms+26ms Time taken to collect garbage.

There is a talk on this topic @ https://www.youtube.com/watch?v=_CruQY55HOk

Diff b/w bitmap.recycle() and bitmap=null

Calling recycle() indicates to the system that you are finished using that resource and that the system may now free the unmanaged memory that it was using. Once you have disposed of a resource in this way, its behaviour is usually undefined (one would reasonably expect it to simply no longer work).

Setting the reference to null afterwards has two benefits:

  • You won't have stale references to objects that won't work when you try to use them
  • The garbage collector will know to clean up the managed side of the bitmap object, freeing even more memory

MonoDroid: About Bitmap.Recycle() and Bitmap.Dispose()

According to Android documentation Bitmap.Recycle() should be enough:

Free the native object associated with this bitmap, and clear the
reference to the pixel data.

Mono for Android documentation says exactly the same.

Also, this question gets a little further on how Bitmap.Recycle works.

Does a byte[] get garbage collected, unlike Bitmap? Or is it the same?

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.



Related Topics



Leave a reply



Submit