surlac
surlac

Reputation: 2961

GC is too active on BitmapFactory.decodeStream()

I have an app which displays grid of thumbnails. The app decodes the input stream to bitmap with BitmapFactory.decodeStream() for each thumbnail in order to display it.

I noticed that GC if super active when I scroll up/down fast enough, which makes the scrolling jerky.

Systrace dump

I tried to isolate the problem and wrote a simple app where I do 10000 decodeStream() calls in a loop and noticed that even though there is enough of memory, the GC is still getting triggered constantly (even if I call bitmap.recycle() after each iteration).

RAM

Question: how to prevent GC from being too active while executing BitmapFactory.decodeStream()?

Upvotes: 1

Views: 146

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007399

The general approach to dealing with memory in Android is the same as the mantra for environmental concerns: reduce, reuse, recycle. "Reduce" means "request less" (e.g., use inSampleSize on BitmapFactory.Options to only load in a downsampled image). "Recycle" means "make sure it can get garbage-collected ASAP".

But, before "recycle" comes "reuse". The Dalvik garbage collector is not a compacting or moving collector, so heap can become fragmented. If you already have an allocation that's the right size, reuse it, rather than let it be collected and then have to re-allocated it again. With bitmaps, that means use inBitmap on BitmapFactory.Options, or use an image-loading library that does this for you.

Will it give the same boost on Android >=5.0

Generally yes, though the exact impacts may vary somewhat.

or the optimizations made on L make the use of inBitmap not necessary (not worth added complexity)?

ART's garbage collector has a variety of improvements. The big one is that it is a compacting or moving collector, though only while your app is in the background, which will not help you much in your case.

However, ART also has a separate area of the heap for large byte arrays (or other large objects that do not have any pointers to other objects inside of them). ART is much more efficient about collecting these, and they will cause less heap fragmentation.

That being said, I'd still use inBitmap. If your minSdkVersion was 21+, maybe you might try skipping inBitmap and see how it goes. But if your minSdkVersion is below 21, you need inBitmap anyway, and I'd just use that code across the board.

Upvotes: 2

Related Questions