I am writing a very memory intensive application for Android Honeycomb, and I've been very careful to recycle()
unused Bitmap
s wherever possible; indeed, this is necessary for the application to work at all, as Bitmap
s are constantly being cycled in and out of memory. However, I have just implemented onConfigurationChanged()
in the Activity
, and so (for a number of reasons) I am trying to put memory freeing routines in onStop()
.
Currently my onStop()
method:
View
s to display a default Drawable
;recycle()
on the Bitmap
s previously used by these View
s;Bitmap
s.Unfortunately, using the Eclipse memory profiler, it seems this is having no effect on the memory usage at all.
As you can imagine, having made so much effort to free resources in a nominally garbage-collected language, I would have hoped for a little more effect. So my question is: what does recycle()
do? Does it actually trigger garbage collection, or will the system hold on to the memory—even if you call System.gc()
—until it feels the need to get rid of something?
NB I know Bitmap
s aren't actually held in the regular heap but I thought calling recycle()
was enough to ensure they were dropped out of the native heap.
PART OF THE ANSWER
I have discovered that if an ImageView
contains a Bitmap
that has been recycled, the Bitmap
data is still retained in memory until setImageBitmap(null)
is called on the ImageView
. This may even be the case if setImageResource(...)
or setImageDrawable(...)
are called (they were, loading in a relatively small nine-patch—however, MAT analysis shows this did not remove the large Bitmap
, which was contained in the private members of the ImageView
). Simply calling this function at onStop()
has culled about 10MB from the heap of our application. Apparently this may not be the case for pre-Honeycomb builds of Android, though.
As Justin says, Bitmap data is not allocated in the VM heap. There is a reference to it in the VM heap (which is small), but the actual data is allocated in the Native heap by the underlying Skia graphics library. [Note that this may have changed in later Android levels, but is true for 2.1 and 2.2] When you do a recycle() that marks both the small portion in the VM heap and the actual data in the native heap as free and available for GC. But the actual collection is performed by two different GC mechanisms. The portion in the VM heap is collected by the Davlik GC - and you can see that happening via DDMS. But the native heap data is collected by the Skia GC, which appears to be lazier (it runs less frequently?). That means that, even with rigorous recycle()s, it is possible to get ahead of the native heap GC. Fortunately there are mechanisms to monitor the state of the native heap. See BitmapFactory OOM driving me nuts.
I have discovered that, in Honeycomb onwards, if an ImageView
contains a Bitmap
that has been recycled, the Bitmap
data is still retained in memory until setImageBitmap(null)
is called on the ImageView. This may even be the case if setImageResource(...)
or setImageDrawable(...)
are called (in this case, a very large bitmap was replaced with a fairly small nine-patch, but only when setImageBitmap(null)
was called before loading the nine-patch was the memory actually disposed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With