Android VM不允许我们分配xx字节

时间:2012-10-27 11:42:33

标签: android memory heap-size

我正在开发一款Android游戏。当我尝试使用3张图像作为背景时问题就出现了。图像为1280x720px和100kb大。 图像真的不是那么大,所以我有点困惑为什么它们应该导致内存问题。

注意:屏幕分辨率为800x400,因此我无法按照因子2调整图像大小,因为suggested on android developer 注意:我正在使用HTC欲望手机(这里是崩溃来了),我也尝试过三星Galaxy S1和三星它的工作正常。

我已经分析了DDMS中的内存,奇怪的是我发现Heap只有3.5mb大。如果我检查rt.MaxMemory(),它说每个应用程序有大约25mb的空间。

我想到的是,堆没有足够快地“更新”以适应更大的照片/应用程序,所以它在加载图像之前崩溃,尽管它很小。有没有办法手动设置堆大小,或者至少告诉它放大?

以下是我加载图片的代码:

        Bitmap floorFront = BitmapFactory.decodeResource(host.getResources(), R.drawable.floor1);
        floorFront = Bitmap.createScaledBitmap(floorFront,host.realWidth,host.realHeight, true);
        floorFront = Bitmap.createBitmap(floorFront, 0, host.realHeight/2, host.realWidth, host.realHeight/2);
        host.addInstance(new Background(0,host.realHeight/2,host,floorFront,1));

        Bitmap floorBack = BitmapFactory.decodeResource(host.getResources(), R.drawable.sand);
        floorBack = Bitmap.createScaledBitmap(floorBack,host.realWidth,host.realHeight, true);
        floorBack = Bitmap.createBitmap(floorBack, 0, host.realHeight/2, host.realWidth, host.realHeight/2);
        host.addInstance(new Background(0,host.realHeight/2,host,floorBack,4));

        Bitmap floorRock = BitmapFactory.decodeResource(host.getResources(), R.drawable.foreground);
        floorRock = Bitmap.createScaledBitmap(floorRock,host.realWidth,host.realHeight, true);
        floorRock = Bitmap.createBitmap(floorRock, 0, host.realHeight/2, host.realWidth, host.realHeight/2);
        host.addInstance(new Background(0,host.realHeight/2,host,floorRock,0));

以下是LogCat的确切错误:

 maxMemory:25165824
 memoryClass:24
 6144000-byte external allocation too large for tgis process.
 Out of memory: Heap Size=4739KB, Allocated=2399KB, Bitmap Size=18668KB
 VM won't let use allocate 6144000bytes

编辑: 现在您说有意义的是位图使用“原始”图像大小而不是压缩。经过一些研究后,似乎在Android 2.2和2.3位图上没有存储在堆中,因此在加载图像后堆不会增加。

我还有一个问题。我们使用这3张图片作为背景。我们现在将在垂直方向上调整它们的大小,但在水平方向上我们仍然需要它们。所以图像仍然是100x720px左右。我们需要3个图像的问题是,所以我们可以单独绘制它们并获得图层效果(我们可以在2个图像之间绘制一些东西)。实现这一目标的最佳方法是什么,以尽可能少的内存来获得理想的效果?

背景: background 中间: middle 前景 foreground

注意:这只是静态背景,动画发生在它们周围和之间。

1 个答案:

答案 0 :(得分:4)

我不知道你从哪里获得1280 x 720像素的位图是100KB。它实际上是几兆字节。以字节为单位,它是1280 * 720 *,但是每个像素有多个字节,对于具有透明度的图像通常为4,对于没有图像的图像通常为2。这是手机加载的大量数据。也许您引用的是压缩图像格式版本的大小,例如PNG。

处理内存使用问题的一些提示:

如果您没有透明度,请在工厂中使用Bitmap.Config.RGB_565输入格式。与ARGB_8888相比,这节省了空间。

在AndroidManifest.xml中的application元素上将largeHeap设置为true。

确保您的位图不会根据设备密度等级自动缩放。例如,将它们放在drawable-nodpi中,或者以编程方式禁用自动缩放,或者为多个可绘制文件夹中的每个密度类提供不同的位图。如果您的位图仅位于可绘制文件夹中,则它将在XHDPI设备上缩放2倍。

回收您未使用的位图,例如:

Bitmap floorFront = BitmapFactory.decodeResource(host.getResources(), R.drawable.floor1);
Bitmap floorFrontScaled = Bitmap.createScaledBitmap(floorFront,host.realWidth,host.realHeight, true);
floorFront.recycle();
floorFront = null;

Bitmap floorFrontCropped = Bitmap.createBitmap(floorFrontScaled, 0, host.realHeight/2, host.realWidth, host.realHeight/2);
host.addInstance(new Background(0,host.realHeight/2,host,floorFrontCropped,1));

您也可以手动运行System.gc()。系统应该在返回OutOfMemoryError之前为您执行此操作,但它不适用于Android中的位图,因为它们在Java之外分配了内存。

请注意,当您在Bitmap中读取时,您实际上可以检查您需要它的大小是否小于其大小的整数除数,然后指定工厂应在加载时跳过像素。这对较小分辨率的设备有帮助,这些设备具有相应较小的内存限制。

如果你没有单独移动这些背景图像,那么将它们全部绘制到一个位图并使用它而不是一次三个。