安卓虚拟机不允许我们分配xx字节

8
我正在开发一个Android游戏。当我尝试使用3张1280x720像素且大小为100kb的图片作为背景时,问题出现了。
这些图片并不是很大,所以我有点困惑为什么它们会引起内存问题。
注意:屏幕分辨率为800x400,因此我无法将图像按2倍比例调整大小,正如 Android开发人员建议的建议。
注意:我正在使用HTC Desire手机(在这里崩溃),我还尝试在三星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上,位图不存储在堆中,因此在加载图像后堆不会增加。
我还有一个问题。我们使用这三张图片作为背景。现在我们会在垂直方向上稍微调整它们的大小,但在水平方向上我们仍然需要它们保持原样。因此,图像仍将约为100x720px。我们需要3张图片的原因是,这样我们可以单独绘制它们并获得层效果(我们可以在两张图片之间绘制某些内容)。实现此目标并尽可能少地使用内存的最佳方法是什么?
背景: background 中间: middle 前景: foreground 注意:这只是静态背景,动画发生在它们周围和之间。

如果您只创建其中的1个,会使用多少内存? - ethrbunny
对于一个文件大小约为2.5MB的程序,如果我打开两个或三个,它就会崩溃。 - Jani
18Mb的“位图大小”出现在哪里?那不是2.5的3倍。 - ethrbunny
它发生在“cluster”的第三行:Bitmap.createBitmap... 这就是问题所在,我不明白它怎么会接近3MB,但即使它是3MB,也比HTC Desire的最大尺寸小8倍。 - Jani
1个回答

4
我不确定你从哪里得到一个1280 x 720像素的位图大小是100KB。实际上它有几兆字节。以字节为单位,它是1280 * 720 * 多少字节每像素,通常对于具有透明度的图像为4,对于没有透明度的图像为2。这是手机加载的巨大数据量。也许你引用的是压缩图像格式版本的大小,如PNG。
解决内存使用问题的一些提示:
如果没有透明度,请在工厂中使用Bitmap.Config.RGB_565输入格式。这与ARGB_8888相比可以节省空间。
在AndroidManifest.xml文件中的应用程序元素上将largeHeap设置为true。
确保您的位图没有根据设备密度类自动缩放。例如,将它们放置在drawable-nodpi中,或通过编程禁用自动缩放,或在多个可绘制目录中为每个密度类提供不同的位图。如果您的位图仅在drawable文件夹中,它将在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之外分配的内存,因此不会自动执行。

请注意,当读取位图时,您实际上可以检查所需大小是否比其大小小一个完整除数,然后指定工厂在加载时跳过像素。这可以在较小分辨率的设备上提供帮助,这些设备的内存限制相应较小。

如果您没有单独移动这些背景图像,则将它们全部绘制到单个位图中,并使用该位图代替三个位图。


3
在清单文件中设置android:largeHeap并不会“减少内存使用量”。它请求为该应用程序提供更多的堆空间,这可能会影响其他应用程序(以及用户)。虽然这是一种有效的技术,但它应该是最后一招的技术,仅用于可以向用户证明这种行为合理的应用程序。 - CommonsWare
是的,我知道它是做什么的。我已经为提示更正了标题文本,谢谢。老实说,由于垃圾收集器无法跟踪这些内容,Android上的OOME崩溃在我的崩溃报告工具中很普遍,因此任何解决方法对用户来说都是最好的选择。不管怎样,这看起来像是一个带有视差滚动背景的游戏,而玩家期望将他们的硬件推向极限。 - Lance Nanek
谢谢,现在我清楚了内存错误的来源。你有什么更多解决问题的建议吗?我编辑了我的第一篇帖子。 - Jani
说实话,在我的许多更复杂的应用程序中,如果不使用OpenGL或一些成熟的技术而必须使用Google的崩溃Bitmap/View垃圾,我会将任何动态缩放的内容更改为每个密度类别的固定大小。因此,如果您有一个得分条,例如,请将其大小设置为48dp(并在drawable-ldpi、drawable-mdpi等中为每个密度类别提供预先调整大小的版本),而不是将其大小设置为屏幕的1/5(通过layout_weight或其他动态大小)。不过,这是在添加立即手动回收和逐个处理位图之后的最后一招。 - Lance Nanek
在相关的 Reddit 帖子中,有人指出了一些额外的提示,例如将 BitmapFactory.Options#inPurgeable 设置为允许清除图像而不是应用程序崩溃,并根据可用内存检查并缩小大小:http://www.reddit.com/r/androiddev/comments/11a5sn/solving_crashes_due_to_high_res_assets_in_android/ - Lance Nanek
显示剩余2条评论

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