应用程序在加载数十个纹理后崩溃

时间:2012-01-08 12:56:44

标签: java android opengl-es png

我注意到当我加载几十个纹理时,我的应用程序崩溃而没有任何通知左右。它只是返回到手机的前一个屏幕。可能是因为手机无法在内存中存储那么多?我不应该在游戏开始之前加载所有纹理吗?

2 个答案:

答案 0 :(得分:2)

你的答案已经作为评论的一部分,但我会在这里写下这个结论:

存储资产的大小无关紧要,因为它们可能已被压缩。重要的是实际工作集的大小。对于图像,您可以将其计算为

width * height * sizeof(pixel)

,其中

sizeof(pixel) = sum[channels]{ sizeof(channel) }

对于1024x1024,4个通道(RGBA),每个通道1个字节,单个纹理的工作集大小为:

1024*1024 = 1Mi
1Mi * 4 * 1B = 4MiB

在27纹理的情况下,这相当于27*4MiB = 108MiB。现在OpenGL在抽象机器上定义,这意味着你不能问它,你需要花多少内存。它会告诉你它是否内存不足。如果不是所有东西都适合视频RAM,OpenGL也可以使用普通的系统RAM。无论哪种方式,在手持设备上,如果尝试上传超过100MiB的纹理数据,您可能会耗尽内存。

  

我不应该在游戏开始之前加载所有纹理吗?

不,你不应该。实际上,更好地“流式传输”游戏内容,按需加载内容。某种垃圾收集或回收计划也有很大帮助。分配纹理很昂贵(即调用glTexImage),而替换数据很便宜(glTexSubImage),所以我建议在纹理管理结构中添加一个“未使用”的计数器。每次绑定纹理并从中绘制时,都将其设置为零。完成一个帧后,增加每个纹理对象的“未使用”计数器。如果需要加载新纹理,则迭代所有纹理对象,选择具有匹配格式(相同大小和通道数)的纹理,按未使用的计数器排序,然后重复使用纹理对象,其中“未使用”值的中位数,即在“未使用”的有序集合的中间。应该释放每个“更高的未使用”纹理,其他纹理保留。如果你需要分配多个纹理(可能),首先从N个中间对象中分配。使用该策略可以为您提供随时可用的纹理对象,并偶尔释放未使用的内存。

答案 1 :(得分:1)

回顾一下评论,通过在RGBA模式下分配总共1024 x 1024像素的纹理,每次纹理每次分配4 MB的视频ram,总计110 MB。

为了避免这种崩溃并与多个Android系统兼容,您应该缩小纹理的大小(有时会降低整体质量)。

一旦没有使用纹理,为了给其他新负载腾出空间,纹理必须卸载是没用的。