5

我们有一个应用程序,我们在其中使用 OpenGL ES 2.0 绘制了许多东西(主要是 OpenStreetMap Tiles,但也有其他图像)。这工作得很好,但有时应用程序在没有任何信息的情况下崩溃 - 这意味着:应用程序只是关闭,而不是崩溃的消息,logcat 中也没有消息。

从实验中我们发现,应用程序在将太多纹理加载到 OpenGL 后会崩溃 ( glGenTextures/glBindTexture) 在三星 Galaxy S3 上的实验中,我们能够加载多达 1800 个 RGB888 标准尺寸为 256x256 的纹理。之后,我们的应用程序崩溃而没有任何错误日志。当我们在加载纹理GL_OUT_OF_MEMORY时不断检查 OpenGL 错误()时,我们不应该收到错误( )吗?GLES20.glGetError

一般问:有没有办法确定 gpu 内存中可用的最大大小,或者至少,我们如何在内存不足时立即收到警告?(问题是我们不知道什么时候应该开始删除句柄,我们希望尽可能长地保留它们中的大部分......)

提前感谢您的任何回复。

4

1 回答 1

13

因此,经过一番研究,我们找到了解决方案。

但首先: 这些方法无济于事,这些方法也无济于事。第一篇文章中提到的方法会让你得到绝对无用的数字,这对你毫无帮助,甚至可能不正确(因为我的 Galaxy S3 的数字比 nexus 7 高得多。但在我们的测试中,nexus 7 可以加载与 S3 相同数量甚至更多的纹理)。

然后让我们继续我们的解决方案 - 我们仍然不确定它是否是最好的,但它会起作用:

看起来您可以在 OpenGL 中保留与可用总 RAM 一样多的纹理。是的,总 RAM,不是堆,也不是与您的应用程序相关的其他东西!这实际上是整个系统的可用 RAM 量,没有任何限制!

因此,一旦您弄清楚了,您只需读出您拥有的可用 RAM 量:

ActivityManager actvityManager = (ActivityManager) mapView.getActivity().getSystemService( Activity.ACTIVITY_SERVICE );
ActivityManager.MemoryInfo mInfo = new ActivityManager.MemoryInfo ();
actvityManager.getMemoryInfo( mInfo );
Log.v("neom","mema " + mInfo.availMem/1024/1024);

最好的地方可能是你的onSurfaceCreated方法或类似的东西。您在那里获得的内存量是您当前拥有的总可用 RAM。大多数情况下,这个值太低了,几乎在任何情况下,你甚至可以分配比你到达那里更多的内存(在我们的测试中,我们总是可以分配大约 30%-50% 的 RAM 比availMem 给我们的内存,直到应用程序崩溃(在 Nexus 上测试7 (+28%)、Galaxy S3 (+36%)、变形金刚 T1 (+57%)、Nexus S (+57%))。这样做的原因是:Android 将在内存真正耗尽之前从未使用的东西、后台进程等中释放内存。

那么这是什么意思?

您可以(几乎)安全地在 OpenGL 中保留与可用 RAM 一样多的“纹理字节”。例如:假设您有 375 MB 的可用 RAM 和每个大小为 256kb 的纹理,您可以在 OpenGL 中保留大约 1500 个纹理,然后再开始删除其中一些(使用 LRU 缓存或类似的东西)。你甚至可以保留更多,但我认为你有这个数量是相当安全的。

Sureley,您也可以availmem更频繁地获得缓存大小,或者您正在对这个新的内存量做什么 - 但我认为如果你这样做一次就足够了onSurfaceCreated- 特别是因为如果你切换,这将再次被读出到另一个应用程序并返回。

于 2013-05-03T06:19:30.447 回答