Android游戏资源加载时内存不足

3
我正在编写一个游戏,目前需要使用大约200个PNG文件,总共约14 MB,大小从250x150到600x400不等(这些是xhdpi可绘制对象,现在我让Android对低dpi进行调整)。问题是,如果在游戏开始时加载它们全部,大约20秒后会出现内存不足错误,无论是在模拟器上(带有1 GB RAM)还是Galaxy S设备(512 MB RAM)上。

我看到过一些资源更大的游戏,甚至有数百MB。这些游戏如何快速处理其资源加载而不超过内存限制?14 MB不应该那么多。

现在我正在使用BitmapFactory.decodeResource()在游戏开始前的几个循环中加载每个位图。我还尝试使用设置为4的BitmapFactory.Options inSampleSize,这解决了内存不足的问题,但仍然需要花费约20秒的时间进行缓慢加载。我也不想这样做,因为如果我将图像缩小4倍,那么考虑hdpi和xhdpi屏幕就没有太大意义了 - 在这些屏幕上,质量会变得更差。我也尝试使用getDrawable(),但没有任何区别。

我还考虑在需要时加载每个资源(游戏开始后),但:

  1. 这样会很慢吗? - 现在系统在每次加载之间分配更多内存,需要100-300毫秒。这将严重降低我的帧率。
  2. 如果我将每个图像缓存一次,那么最终我将需要在同一级别中使用它们全部,因此这不应该解决内存不足的问题。

我知道位图在内存中占用的空间比磁盘上的PNG文件多 - 当分配约40 MB时,我会遇到错误。难道没有一种方法只需将14 MB加载到内存中,并根据需要构建位图,或者换取更多的可用内存而放弃一点速度(这是一个相当基本的2D游戏,因此我实际上不需要太多处理能力或最大fps)吗?

另外,我有很多包含约10-16帧的小动画。每个都是单独的文件。将它们合并为一个文件是否有任何好处?我看不出它对内存使用有所帮助,但它可以帮助减少加载时间吗?

更新:我将代码更改为加载每个帧,显示它,然后回收(recycle())。这导致我能够看到的帧率低于5 FPS,因此我认为我无法这样做。


你确定你的游戏每时每刻都需要这些图片吗? - Egor
@Egor - 由于它们大多是约10个不同对象的框架,因此它们不会同时出现在屏幕上。但在2-3秒的间隔内,很有可能大部分甚至全部都会显示出来。 - IVlad
主要问题在于许多设备(和模拟器,我相信)的堆大小仅为16 MB。当您使用BitmapFactory将14 MB的图像加载到内存中时,每个图像都会被解码为位图,从而远远超出了分配的16 MB内存。如果您确实需要这样大的图像,则需要找到一种方法,在需要时动态地加载/释放它们。否则,您将不得不使用较小的位图。此外,请记住,加载较小尺寸的图像比加载大图像并让Android缩小它们要快得多。 - Aleks G
@Aleks G - 你确定16 MB的限制吗?仿真器似乎在崩溃之前将堆增长到约44 MB。我还没有尝试过,但我无法想象从资源加载图像,然后释放它们以使我保持合理的FPS。也许我必须调整它们的大小,但我仍然希望有更好的方法。 - IVlad
更新:我改变了我的代码,加载每一帧,显示它,然后将其“回收”。这导致我可以看到的帧速率小于5 FPS,所以我认为我做不到这一点。 - IVlad
1个回答

0

尝试使用Bitmap的SoftReference缓存来扩展您的选项(2)。这样,您只需要加载一次Bitmap,但如果VM内存不足,则这将是首个被释放的候选项。可以像这样实现:

public class MemoryCache {
    private HashMap<String, SoftReference<Bitmap>> cache=new HashMap<String, SoftReference<Bitmap>>();

    public Bitmap get(String id){
        if(!cache.containsKey(id))
            return null;
        SoftReference<Bitmap> ref=cache.get(id);
        return ref.get();
    }

    public void put(String id, Bitmap bitmap){
        cache.put(id, new SoftReference<Bitmap>(bitmap));
    }

    public void clear() {
        cache.clear();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接