0

I have been building an Android game which loads, scales, and displays bitmaps. Whenever I start loading a batch of bitmaps, the memory profile of the game on my LG Nexus 4 skyrockets. Then when I start interacting with the game (touching the screen to walk, etc), the memory consumption drops radically, and then raises and drops small amounts with regularity as the tiles background scrolls by (images are unloaded as the drop off the screen).

I've recently added more bitmaps at a specific point in the game and it takes me all the way to 550 MB and then crashes with an out of memory error.

My art assets total less than 13 MB and I never have them all loaded at the same time. Why is my game consuming massive amounts of memory at certain points?

enter image description here

Here is my bitmap loading code:

public class BackgroundBitmapLoader implements Runnable {

    public GameView gameView;
    public BackgroundTile backgroundTile;
    public Bitmap bitmap;
    public int drawableID;
    public Context context;
    public int scaledWidth;
    public int scaledHeight;

    public BackgroundBitmapLoader(GameView gameView, BackgroundTile backgroundTile, Context context, int drawableID, int scaledWidth, int scaledHeight) {
        this.gameView = gameView;
        this.backgroundTile = backgroundTile;
        this.context = context;
        this.drawableID = drawableID;
        this.scaledHeight = scaledHeight;
        this.scaledWidth = scaledWidth;
    }

    public void run() {
        bitmap = BitmapFactory.decodeResource(context.getResources(), drawableID);
        bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
        backgroundTile.setBitmap(bitmap);
        gameView.incrementLoadedBitmapCount();
    }
}

And here is the code I use to unload bitmaps when they move off the screen or are no longer needed:

public class BitmapUnloader implements Runnable {

    Bitmap bitmap;

    public BitmapUnloader(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    public void run() {
        bitmap.recycle();
    }
}
fadden
  • 51,356
  • 5
  • 116
  • 166
Joe
  • 376
  • 4
  • 13

1 Answers1

2

The size of the png or jpg files is not the size in memory. PNG and JPG are compressed. In memory Bitmaps are uncompressed. For a standard ARGB format, that means it takes 4 bytes per pixel in memory, or 4*width*height bytes total (plus a small amount of overhead, but that can be ignored compared to the image data). So the fact they're only 13 MB on disk doesn't mean that it isn't several times that in memory.

Secondly, Java is a garbage collected language. This means that the amount of memory used doesn't decrease until the GC runs and actually collects the memory. Calling recycle doesn't do that, it just releases references to it so that the GC can free it the next time it does run. Which makes it a good thing to do, but until the GC actually decides to run you will see spikes.

As for your actual code- your scaling is inefficient. It creates 2 copies of the bitmap object- scaled and unscaled. You should only create 1. You can scale it by using the BitmapFactory.Options you can pass to Bitmap factory.

Beyond that there's nothing I see in the code posted, but that doesn't mean there aren't other problems elsewhere.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Thanks for the fast answer. Can you share the syntax for creating just one bitmap? Or a link? – Joe Mar 04 '16 at 23:41
  • Scaling down can be found at http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. Scaling up should be similar. Note that while it calls decode twice, the first time it only decodes the header, which is very quick and requires almost no memory (the first time is to get the size of the bitmap in the file). – Gabe Sechan Mar 04 '16 at 23:54
  • Thanks for your help! – Joe Mar 04 '16 at 23:58