我们有一个应用程序,我们用OpenGL ES 2.0绘制很多东西(主要是OpenStreetMap Tiles,还有其他图像)。这样做效果很好,但有时应用程序崩溃而没有任何信息 - 这意味着:应用程序只是关闭,而不是消息崩溃,而且logcat中没有消息。
我们已经发现实验,在将太多纹理加载到OpenGL(glGenTextures/glBindTexture
)后,应用程序崩溃了
在三星Galaxy S3的实验中,我们能够在RGB888标准中加载多达1800个纹理,尺寸为256x256。之后,我们的应用程序崩溃,没有任何错误日志。当我们在加载纹理时不断检查OpenGL错误(GL_OUT_OF_MEMORY
)时,我们不应该收到错误(GLES20.glGetError
)吗?
一般要求: 有没有办法确定gpu内存中可用的最大大小,或者至少,我们如何在内存不足时收到警告? (问题是我们不知道什么时候我们应该开始删除句柄,我们希望尽可能长时间地保留它们...)
提前感谢您的回复。
答案 0 :(得分:13)
经过一些研究,我们找到了解决方案。
但首先: These methods无济于事,也不会these。 第一篇文章中提到的方法将为你提供绝对无用的数字,这些数字根本无法帮助你,甚至可能都不正确(因为我的星系S3得到的数字远远高于nexus 7.但在我们的测试中,nexus 7可以加载与S3相同数量甚至更多的纹理。
然后让我们继续我们的解决方案 - 我们仍然不确定它是最好的,但它会起作用:
看起来你可以在OpenGL中保留尽可能多的纹理,因为你有免费的总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
方法或类似的方式。
你在那里获得的内存量是你目前拥有的总可用内存。大多数情况下这个值太低了,几乎在任何情况下你甚至可以分配比你到那里更多的内存(在我们的测试中,我们可以总是分配比availMem给我们多大约30%-50%的RAM,直到应用程序崩溃(在Nexus上测试) 7(+ 28%),Galaxy S3(+ 36%),变压器T1(+ 57%),Nexus S(+ 57%))。原因是:在真正耗尽内存之前,Android会从未使用的东西,后台进程等中释放内存。
那是什么意思?
你可以(几乎)安全地在OpenGL中保留尽可能多的“纹理字节”,因为你有可用的RAM。例如:假设你有375 MB的可用RAM和纹理,每个都有256kb的大小,你可以在开始删除其中一些(使用LRU缓存或类似的东西)之前在OpenGL中保留大约1500个纹理。你甚至可以保留更多,但我认为你这个数量非常安全。
Sureley你也可以更频繁地获得availmem
并且恰好适合你的缓存大小或你正在做的新内存量 - 但我认为如果你在{{1}中执行一次就足够了 - 特别是因为如果你切换到另一个应用程序并返回它将会再次读出。