35

我正在使用 OpenGL ES 开发一个 2D iPhone 游戏,我一直在达到 24 MB 内存限制——我的应用程序不断崩溃并显示错误代码 101。我非常努力地寻找内存的去向,但 Instruments 中的数字仍然很多比我预期的要大。

我使用 Memory Monitor、Object Alloc、Leaks 和 OpenGL ES 工具运行应用程序。当应用程序被加载时,可用物理内存从 37 MB 下降到 23 MB,Object Alloc 稳定在 7 MB 左右,Leaks 显示两个或三个泄漏大小为几个字节,Gart 对象大小约为 5 MB,Memory Monitor 说应用程序占用大约 14 MB 的实际内存。我很困惑内存去了哪里——当我深入研究对象分配时,大部分内存都在纹理中,正如我所期望的那样。但是我自己的纹理分配计数器和 Gart 对象大小都同意纹理应该占用大约 5 MB。

我不知道分配任何其他值得一提的东西,并且 Object Alloc 同意。记忆去哪儿了?(如果这还不够,我很乐意提供更多细节。)


更新:我真的试图找到我可以分配这么多内存的地方,但没有结果。让我疯狂的是对象分配(~7 MB)和内存监视器(~14 MB)显示的实际内存使用量之间的差异。即使我忘记了巨大的泄漏或大块内存,它们仍然应该出现在 Object Allocations中,不是吗?

我已经尝试过通常的 嫌疑人,即。与UIImage它的缓存,但这并没有帮助。有没有办法逐行跟踪内存使用“调试器风格”,观察每条语句对内存使用的影响?


到目前为止我发现了什么:

  1. 我真的使用那么多内存。衡量真正的内存消耗并不容易,但是经过大量计算后,我认为内存消耗确实很高。我的错。

  2. 我发现没有简单的方法来测量使用的内存。内存监视器的数字是准确的(这些是真正重要的数字),但内存监视器无法告诉您内存的确切位置。Object Alloc 工具对于跟踪实际内存使用情况几乎毫无用处。当我创建纹理时,分配的内存计数器会上升一段时间(将纹理读入内存),然后下降(将纹理数据传递给 OpenGL,释放)。这没关系,但并不总是会发生——有时即使在纹理被传递到 OpenGL 并从“我的”内存中释放之后,内存使用率仍然很高。这意味着 Object Alloc 工具显示的分配内存总量小于实际总内存消耗,但大于实际消耗减去纹理 ( real – textures < object alloc < real)。去搞清楚。

  3. 我误读了编程指南。24 MB 的内存限制适用于纹理和表面,而不是整个应用程序。实际的红线稍远一些,但我找不到任何硬数字。共识是 25-30 MB 是上限。

  4. 当系统内存不足时,它开始发送内存警告。我几乎没有什么可释放的,但其他应用程序确实会将一些内存释放回系统,尤其是 Safari(它似乎正在缓存网站)。当内存监视器中显示的可用内存变为零时,系统开始查杀。

我不得不硬着头皮重写代码的某些部分以提高内存效率,但我可能仍在推动它。如果我要设计另一个游戏,我肯定会想到一些资源分页。对于当前的游戏,这非常困难,因为它一直在运动,并且加载纹理会妨碍,即使在另一个线程中完成。我会对其他人如何解决这个问题很感兴趣。

请注意,这些只是我的观点,不必太准确。如果我发现有关此主题的更多信息,我将更新该问题。我会保持这个问题的开放性,以防了解这个问题的人愿意回答,因为这些都是比其他任何东西更多的解决方法和猜测。

4

5 回答 5

11

我非常怀疑这是 Instruments 中的一个错误。

首先,阅读Jeff Lamarche 的这篇关于 openGL 纹理的博文

  • 有一个如何加载纹理而不导致泄漏的简单示例
  • 了解“小”图像在加载到 OpenGL 后如何实际使用“大量”内存

摘抄:

纹理,即使它们是由压缩图像制成的,也会占用大量应用程序的内存堆,因为它们必须在内存中扩展才能使用。每个像素占用 4 个字节,因此忘记释放纹理图像数据会很快耗尽内存。

其次,可以使用 Instruments 调试纹理内存。有两种分析配置:OpenGL ES AnalyzerOpenGL ES Driver。您需要在设备上运行这些,因为模拟器不使用 OpenGL。只需从 XCode 中选择 Product->Profile 并在 Instruments 启动后查找这些配置文件。


有了这些知识,这就是我要做的:

  • 检查您是否没有泄漏内存——这显然会导致此问题。
  • 确保您没有访问自动释放的内存——崩溃的常见原因。
  • 创建一个单独的测试应用程序并单独(和组合)加载纹理以找出导致问题的纹理(或其组合)。

更新:在考虑了您的问题后,我一直在阅读Apple 的 OpenGL ES Programming Guide,它提供了非常好的信息。强烈推荐!

于 2010-03-19T08:28:08.780 回答
3

一种方法是开始注释代码并检查错误是否仍然发生。是的,它既乏味又简单,但如果你知道错误在哪里,它可能会有所帮助。

它崩溃的地方就是它崩溃的原因,等等。

于 2008-12-16T01:15:02.767 回答
2

嗯,这不是很多细节,但如果泄漏没有告诉你泄漏在哪里,有两个重要的选择:

[i] 泄漏错过了泄漏 [ii] 内存实际上并没有被泄漏

修复 [i] 非常困难,但正如 Eric Albert 所说,向 Apple 提交错误报告会有所帮助。[ii] 表示您正在使用的内存仍然可以在某个地方访问,但也许您已经忘记了它。是否有任何列表在增长,而不会丢弃旧条目?是否有很多缓冲区被重新分配()?

于 2008-12-13T23:41:53.890 回答
2

对于那些在 2012 年之后看到这个的人:

真正加载到设备物理内存中的内存是 VM Tracker Instrument 中的驻留内存。

Allocation Instrument 只标记 malloc/[NSObject alloc] 和一些框架缓冲区创建的内存,例如,Allocation Instrument 中不包含解压缩的图像位图,但它总是占用大部分内存。

Please Watch WWDC 2012 Session 242 iOS App Performance: Memory to get the information from Apple.

于 2013-08-22T01:56:03.723 回答
0

这对您没有特别的帮助,但如果您发现记忆工具没有提供您需要的所有数据,请在 bugreport.apple.com 提交错误。附上你的应用程序的副本,并说明这些工具如何未能满足你的分析,Apple 会看看他们是否可以改进这些工具。谢谢!

于 2008-12-12T19:56:41.010 回答