了解iPhone上的内存消耗

我正在使用OpenGL ES开发2D iPhone游戏,并且一直保持24 MB的内存限制 – 我的应用程序不断崩溃,出现错误代码101.我试图很难find内存的位置,但乐器中的数字仍然很多比我所期望的要大

我用Memory Monitor,Object Alloc,Leaks和OpenGL ES仪器运行了这个应用程序。 当应用程序被加载时,空闲的物理内存从37 MB降低到23 MB,Object Alloc约为7 MB,泄漏显示两个或三个泄漏几个字节,Gart对象大小约为5 MB,内存监视器显示应用程序占用大约14 MB的实际内存。 我感到困惑的是记忆力在哪里 – 当我深入研究Object Allocations时,大部分的记忆都在纹理中,完全如我所料。 但是我自己的纹理分配计数器和Gart对象大小都认为纹理应该占用5MB左右的空间。

我不知道分配任何值得一提的东西,而对象Alloc也同意。 记忆在哪里? (如果这还不够,我很乐意提供更多细节。)


更新:我真的试图find我可以分配这么多的内存,但没有结果。 什么驱使我疯狂是对象分配(〜7 MB)和实际内存使用情况(如内存监视器(〜14 MB)所示)之间的差异。 即使存在大量的泄漏或者大量的记忆,我仍然忘记了,这个应该仍然出现在对象分配中 ,不是吗?

我已经尝试了通常的 嫌疑犯 ,即。 UIImage的caching,但没有帮助。 有没有一种方法可以逐行跟踪内存使用“debugging器风格”,观察每条语句对内存使用情况的影响?


到目前为止我发现的是:

  1. 我真的正在使用那么多的记忆。 测量真正的内存消耗并不容易,但经过大量计算,我认为内存消耗真的很高。 我的错。

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

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

  4. 当系统内存不足时,系统开始发送内存警告。 我几乎没有什么可以免费的,但其他应用程序确实释放了一些内存回到系统,特别是Safari(这似乎是caching网站)。 当内存监视器中显示的空闲内存变为零时,系统开始查杀。

我不得不咬紧牙关,重写代码的某些部分,以便在内存方面更加高效,但我可能仍在推动它。 如果我要devise另一个游戏,我肯定会想到一些资源分页。 在当前的游戏中,这是非常困难的,因为事物总是在运动,加载纹理会阻碍,即使在另一个线程中完成。 我会对其他人如何解决这个问题感兴趣。

请注意,这些只是我的看法,不一定非常准确。 如果我在这个话题上发现更多的话,我会更新这个问题。 如果有人理解这个问题,我会保持这个问题的答案,因为这些都是更多的解决办法和猜测。

我非常怀疑这是一个仪器的错误。

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

  • 有一个简单的例子,如何加载纹理而不会造成泄漏
  • 了解如何将“小”图像加载到openGL中,然后使用“大量”内存

摘抄:

即使纹理是由压缩的图像构成的,也会使用很多应用程序的内存堆,因为它们必须在内存中进行扩展才能使用。 每个像素占用四个字节,所以忘记释放您的纹理图像数据可以很快消耗你的记忆。

其次,可以使用乐器debugging纹理记忆。 有两种性能分析configuration: OpenGL ES分析器和OpenGL ES驱动程序 。 您将需要在设备上运行这些,因为模拟器不使用OpenGL。 只需从XCode中selectProduct-> Profile并在仪器启动后查找这些configuration文件。


有了这些知识,下面是我要做的事情:

  • 检查你没有泄漏记忆 – 这显然会导致这个问题。
  • 确保你不访问自动释放的内存 – 崩溃的常见原因。
  • 创build一个单独的testing应用程序,并单独加载纹理(和组合)以查明造成问题的纹理(或其组合)。

更新:考虑到你的问题,我一直在阅读苹果的OpenGL ES编程指南 ,它有非常好的信息。 强烈推荐!

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

它在哪里崩溃是为什么它崩溃等

Hrmm,这不是很多细节,但是如果泄漏不能告诉你泄漏的位置,有两个重要的select:

[i]泄漏漏洞[ii]记忆没有被泄漏

修复[i]是相当困难的,但埃里克阿尔伯特说,向苹果提交错误报告将有所帮助。 [ii]意味着你正在使用的内存仍然可以访问,但也许你已经忘记了。 任何列表都在增长,而不会抛出旧的条目? 是否有任何缓冲区被realloc()编辑了很多?

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

真正加载到设备物理内存中的内存是VM跟踪器仪器中的驻留内存。

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

请观看WWDC 2012 Session 242 iOS应用程序性能:内存获取来自Apple的信息。

这并没有特别的帮助你,但是如果你发现内存工具不能提供你所需要的所有数据,请在bugreport.apple.com上提交一个bug。 附上您的应用程序的副本,并描述工具如何不足以进行分析,苹果将会看看他们是否可以改进这些工具。 谢谢!