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

发布于 2024-12-25 13:07:39 字数 96 浏览 1 评论 0原文

我注意到,当我加载几十个纹理时,我的应用程序会在没有任何通知的情况下崩溃。它只是返回到手机的上一个屏幕。难道是因为手机内存无法存储那么多内容?我不应该在游戏开始前加载所有纹理吗?

I noticed that when I load up a few dozen textures, my app crashes without any notice or so. It just returns to the phone's previous screen. Could it be because the phone cannot store that much in the memory? Should I not load all the textures before the game starts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月寒剑心 2025-01-01 13:07:39

作为评论的一部分,您已经得到了答案,但我将在这里写下这个结论:

存储中资产的大小并不重要,因为它们可能被压缩。重要的是实际工作集的大小。对于图像,您可以计算如下:

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 个中值对象中进行分配。使用该策略可以让您提供随时可用的纹理对象,并且有时还可以释放未使用的内存。

You got your answer already as part of the comments, but I'll write this conclusion here:

The size of your assets in storage doesn't matter, as they are probably compressed. What matters is the size of the actual working set. In the case of images you can calculate it as

width * height * sizeof(pixel)

where

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

In the case of 1024x1024, 4 channels (RGBA), 1 byte per channel your working set size of a single texture would be:

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

In the case of 27 texture this amounts to 27*4MiB = 108MiB. Now OpenGL defined in terms on an abstract machine, which means you cannot ask it, how many memory there is for you to spend. It will just tell you if it runs out of memory. OpenGL may also use normal system RAM if not everything fits into video RAM. Either way, on a handheld device you'll likely run out of memory if trying to upload over 100MiB of texture data.

Should I not load all the textures before the game starts?

No, you should not. It is in fact better to "stream" your game's contents, load things on demand. Also some kind of garbage collection or recycling scheme helps a lot. Allocating a texture is expensive (i.e. a call to glTexImage), whereas replacing the data is cheap (glTexSubImage), so what I suggest is adding a "unused" counter to your texture management structure. Everytime you bind the texture and draw from it, you set it to zero. After finishing a frame increment the "unused" counter of each texture object. If you need to load a new texture you iterate over all texture objects, select those with a matching format (same size and number of channels), sorted by the unused counter, then reuse the texture object with the median of the "unused" values, i.e. in the middle of the sorted set of "unused". Every "higher unused" texture should be freed, the others stay as reserve. If you need to allocate more than one texture (likely) first allocate from the N median objects. Using that strategy keeps you an supply of ready to use texture object and also occasionally frees up unused memory.

醉殇 2025-01-01 13:07:39

回顾一下评论,通过分配如此多的纹理(在 RGBA 模式下总共 27 个 1024 x 1024 像素),您每次为每个纹理分配 4 MB 的视频 RAM,总共 110 MB。

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

说纹理一旦不再使用就必须卸载,以便为其他新加载腾出空间,这是毫无意义的。

To recap the comments, by allocating so may textures, 27 in total of a 1024 by 1024 pixels in an RGBA mode, you allocate 4 MB of video ram each time per texture, for a total of 110 MB.

In order to avoid this kind of crashes and to be compatible with multiple Android systems, you should downsize the size of the textures (sometimes decreasing the overall quality).

Is is useless to say that the textures must be unloaded once they are not used anymore in order to make room for other new loads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文