1

I have the following code in an Activity. Ultimately, I'm trying to do frame animation but the GC is killing performance. I've tried explicit recycles but it makes no difference.

I'm also aware that I can reuse the bitmap with BitmapFactor.Options.inBitmap and that indeed resolves the issue but limits me to API >= 11 which is not an option.

This code merely illustrates the problem. It is not part of my app:

        Log.d("GC_badness", "0: " + SystemClock.uptimeMillis());
        Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "1: " + SystemClock.uptimeMillis());
        image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "2: " + SystemClock.uptimeMillis());
        image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "3: " + SystemClock.uptimeMillis());
        image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "4: " + SystemClock.uptimeMillis());
        image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "5: " + SystemClock.uptimeMillis());
        image = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
        Log.d("GC_badness", "6: " + SystemClock.uptimeMillis());

This results in the following log entries. Each bitmap load from a jpg resource results in at least 3 garbage collections and as many as 8. Most of the time they collect nothing or next to nothing. The heap isn't growing, even though there are multiple messages saying that it is. That also is quite confusing.

I'm stumped. I can't find a way to reuse my bitmap pre-API 11 and I can't live with the huge delays imposed by all of these useless garbage collections.

04-07 18:17:51.860: D/GC_badness(7510): 0: 360583998
04-07 18:17:51.900: D/dalvikvm(7510): GC_FOR_ALLOC freed 34K, 5% free 6320K/6595K, paused 32ms
04-07 18:17:51.900: I/dalvikvm-heap(7510): Grow heap (frag case) to 7.744MB for 1584016-byte allocation
04-07 18:17:51.950: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 5% free 7867K/8199K, paused 27ms
04-07 18:17:52.000: D/dalvikvm(7510): GC_CONCURRENT freed <1K, 5% free 7868K/8199K, paused 2ms+3ms
04-07 18:17:52.030: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 5% free 7868K/8199K, paused 31ms
04-07 18:17:52.030: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 704016-byte allocation
04-07 18:17:52.070: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 4% free 8555K/8903K, paused 37ms
04-07 18:17:52.070: D/dalvikvm(8107): GC_FOR_ALLOC freed 1464K, 39% free 17183K/27911K, paused 62ms
04-07 18:17:52.100: D/GC_badness(7510): 1: 360584238
04-07 18:17:52.100: D/dalvikvm(8189): GC_CONCURRENT freed 286K, 8% free 6917K/7495K, paused 17ms+3ms
04-07 18:17:52.110: D/dalvikvm(7510): GC_CONCURRENT freed 1546K, 22% free 7009K/8903K, paused 2ms+2ms
04-07 18:17:52.150: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 22% free 7008K/8903K, paused 32ms
04-07 18:17:52.150: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 1584016-byte allocation
04-07 18:17:52.200: D/dalvikvm(7510): GC_FOR_ALLOC freed 0K, 4% free 8555K/8903K, paused 37ms
04-07 18:17:52.250: D/dalvikvm(7510): GC_CONCURRENT freed <1K, 4% free 8555K/8903K, paused 2ms+2ms
04-07 18:17:52.280: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 4% free 8555K/8903K, paused 30ms
04-07 18:17:52.280: I/dalvikvm-heap(7510): Grow heap (frag case) to 9.086MB for 704016-byte allocation
04-07 18:17:52.310: D/dalvikvm(7510): GC_FOR_ALLOC freed 0K, 4% free 9243K/9607K, paused 23ms
04-07 18:17:52.330: D/dalvikvm(8107): GC_CONCURRENT freed 588K, 34% free 18618K/27911K, paused 4ms+5ms
04-07 18:17:52.350: D/GC_badness(7510): 2: 360584482
04-07 18:17:52.350: D/dalvikvm(7510): GC_CONCURRENT freed 1546K, 20% free 7696K/9607K, paused 1ms+2ms
04-07 18:17:52.380: D/dalvikvm(7510): GC_FOR_ALLOC freed 688K, 28% free 7008K/9607K, paused 22ms
04-07 18:17:52.380: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 1584016-byte allocation
04-07 18:17:52.400: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 11% free 8555K/9607K, paused 21ms
04-07 18:17:52.440: D/GC_badness(7510): 3: 360584577
04-07 18:17:52.450: D/dalvikvm(7510): GC_CONCURRENT freed <1K, 4% free 9243K/9607K, paused 1ms+2ms
04-07 18:17:52.470: D/dalvikvm(7510): GC_FOR_ALLOC freed 2234K, 28% free 7008K/9607K, paused 20ms
04-07 18:17:52.470: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 1584016-byte allocation
04-07 18:17:52.500: D/dalvikvm(7510): GC_FOR_ALLOC freed 0K, 11% free 8555K/9607K, paused 29ms
04-07 18:17:52.510: D/dalvikvm(8107): GC_CONCURRENT freed 1785K, 33% free 18832K/27911K, paused 2ms+5ms
04-07 18:17:52.530: D/GC_badness(7510): 4: 360584668
04-07 18:17:52.540: D/dalvikvm(7510): GC_CONCURRENT freed <1K, 4% free 9243K/9607K, paused 1ms+2ms
04-07 18:17:52.570: D/dalvikvm(7510): GC_FOR_ALLOC freed 2234K, 28% free 7008K/9607K, paused 28ms
04-07 18:17:52.570: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 1584016-byte allocation
04-07 18:17:52.590: D/dalvikvm(7510): GC_FOR_ALLOC freed <1K, 11% free 8555K/9607K, paused 22ms
04-07 18:17:52.620: D/dalvikvm(7510): GC_CONCURRENT freed <1K, 4% free 9243K/9607K, paused 3ms+2ms
04-07 18:17:52.630: D/GC_badness(7510): 5: 360584765
04-07 18:17:52.650: D/dalvikvm(7510): GC_FOR_ALLOC freed 2235K, 28% free 7008K/9607K, paused 21ms
04-07 18:17:52.650: I/dalvikvm-heap(7510): Grow heap (frag case) to 8.416MB for 1584016-byte allocation
04-07 18:17:52.680: D/dalvikvm(7510): GC_FOR_ALLOC freed 0K, 11% free 8555K/9607K, paused 27ms
04-07 18:17:52.710: D/GC_badness(7510): 6: 360584844
trincot
  • 317,000
  • 35
  • 244
  • 286
Doug Gerecht
  • 404
  • 4
  • 9

1 Answers1

1

Why do you want to reuse the image?

Dont give the garbage collector a chance to collect something. Basically every object you define locally will sooner or later be collected.

Do not reuse your image Variable. Make a imagearray and the images prior your animation code (best would be, to load during the actiity is created). Or consider to use an ObjectPool for your images.

Here is a good SO answer on how to aboid Garbage collection.

And finally you can find plenty of information on how to avoid Garbage collection when you google for eg. "how to avoid garbage collection android".

Community
  • 1
  • 1
KarlKarlsom
  • 5,868
  • 4
  • 29
  • 36
  • I just used a single image in the sample code. In the app I'm displaying many images. On a high res screen they are large (1.5MB) so it's not feasible to load in very many of the up them up front. I'll chew through the heap pretty fast. I can load them in groups but if each load causes a 100ms pause due to 4 or 5 GC's, they won't keep up with the frame rate. I'd love to manage my own bitmaps but the BitmapFactory in the early API's just doesn't support it. Short of coding my own jpg loader to get around BitmapFactory's reallocating Bitmaps at every call I'm not sure what I can do. – Doug Gerecht Apr 08 '12 at 02:46