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

Android应用程序的内存消耗超过所有位图的总和,android,android-bitmap,Android,Android Bitmap,我一直在开发一款Android游戏,可以加载、缩放和显示位图。每当我开始加载一批位图时,我的LG Nexus 4上游戏的内存配置文件就会猛增。然后,当我开始与游戏交互时(触摸屏幕行走等),内存消耗会急剧下降,然后随着背景的滚动,有规律地增加和减少少量内存(图像从屏幕上卸载) 我最近在游戏中的某个特定点添加了更多位图,它一直占用我550 MB的内存,然后由于内存不足而崩溃 我的艺术资产总计不到13MB,而且我从未同时加载所有这些资产。为什么我的游戏在某些时候会消耗大量内存 这是我的位图加载代码:

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

我最近在游戏中的某个特定点添加了更多位图,它一直占用我550 MB的内存,然后由于内存不足而崩溃

我的艺术资产总计不到13MB,而且我从未同时加载所有这些资产。为什么我的游戏在某些时候会消耗大量内存

这是我的位图加载代码:

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个*宽度*高度字节(加上少量开销,但与图像数据相比可以忽略)。因此,磁盘上只有13MB的容量并不意味着内存中的容量不是13MB的几倍

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

至于您的实际代码,您的扩展效率很低。它创建位图对象的2个副本-缩放和未缩放。您应该只创建1。您可以使用位图工厂对其进行缩放。您可以将选项传递给位图工厂


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

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

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

至于您的实际代码,您的扩展效率很低。它创建位图对象的2个副本-缩放和未缩放。您应该只创建1。您可以使用位图工厂对其进行缩放。您可以将选项传递给位图工厂


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

感谢您的快速回答。你能分享一下创建一个位图的语法吗?或链接?可在上找到缩小比例。扩大规模应该是类似的。请注意,虽然它调用decode两次,但第一次它只解码头,这非常快,几乎不需要内存(第一次是获取文件中位图的大小)。感谢您的帮助!谢谢你的快速回答。你能分享一下创建一个位图的语法吗?或链接?可在上找到缩小比例。扩大规模应该是类似的。请注意,虽然它调用decode两次,但第一次它只解码头,这非常快,几乎不需要内存(第一次是获取文件中位图的大小)。感谢您的帮助!