Android 应用中的内存消耗超过了所有位图的总和

Memory consumption in Android app exceeds the sum of all bitmaps

我一直在构建一个 Android 游戏,它可以加载、缩放和显示位图。每当我开始加载一批位图时,我的 LG Nexus 4 上游戏的内存配置文件就会飙升。然后当我开始与游戏互动时(触摸屏幕走路等),内存消耗急剧下降,然后随着瓷砖背景滚动而有规律地增加和减少少量(图像随着屏幕的下降而卸载) .

我最近在游戏中的特定点添加了更多位图,它使我一直到 550 MB,然后因内存不足错误而崩溃。

我的美术资源总计不到 13 MB,而且我从来没有同时加载过它们。为什么我的游戏在某些时候会消耗大量内存?

这是我的位图加载代码:

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();
    }
}

下面是当位图离开屏幕或不再需要时我用来卸载位图的代码:

public class BitmapUnloader implements Runnable {

    Bitmap bitmap;

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

    public void run() {
        bitmap.recycle();
    }
}

png 或jpg 文件的大小不是内存中的大小。 PNG 和 JPG 被压缩。在内存中位图是未压缩的。对于标准的 ARGB 格式,这意味着内存中每个像素需要 4 个字节,或者总共 4*width*height 字节(加上少量开销,但与图像数据相比可以忽略不计)。所以它们在磁盘上只有 13 MB 的事实并不意味着它不是内存中的几倍。

其次,Java是一种垃圾回收语言。这意味着直到 GC 运行s 并实际收集内存时,使用的内存量才会减少。调用回收不会那样做,它只是释放对它的引用,以便 GC 可以在下次执行时释放它 运行。这是一件好事,但在 GC 真正决定 运行 之前,您会看到尖峰。

至于您的实际代码 - 您的缩放效率很低。它创建 2 个位图对象副本 - 缩放和未缩放。您应该只创建 1 个。您可以使用可以传递给位图工厂的 BitmapFactory.Options 来缩放它。

除此之外,我在发布的代码中没有看到任何问题,但这并不意味着其他地方没有其他问题。