在CocoaTouch(iPhone OS)中,如果Instruments泄漏工具无法找到泄漏,我该如何查找/消除泄漏?

4
我有一个在模拟器中运行良好的iPhone应用程序。它对内存警告做出了良好的响应,通过清除一切非绝对必要的东西来释放内存。当我在设备上运行它时,它也可以正常运行。但是在使用一定时间后,它会崩溃并显示错误代码101 - 从我所知道的情况来看,这是由于内存使用情况导致操作系统将其杀死。我可以看到内存警告(我正在记录它),我的应用程序对此做出了响应,但很快之后就会死机。
如果我在仪器中查看应用程序(无论是在设备上还是在模拟器中),它都不会发现任何泄漏。此外,净内存使用量在600-700k字节范围内。从我的应用程序的不同视图转换会增加内存使用量(如预期),但是当视图和控制器被释放和dealloc'd时,内存使用量从未降至低点。然而,添加的通常只是1000-2000字节左右。因此,虽然泄漏没有显示任何泄漏,但我怀疑存在某些问题。我还查看了所有分配的对象,并且所有对象似乎都按预期回收了。我看到的唯一不断增加的对象是GeneralBlock-N(其中N是某个数字)。
我应该不关注仪器的净使用量数字吗?在尝试诊断问题时,下一步应该是什么?补充:我没有调用malloc()或任何返回我负责的缓冲区的CoreFoundation库。我进行的唯一非Obj-C调用是记录语句到NSLog中。

你是不是以其他方式分配内存然后没有释放它呢?比如使用CoreFoundation库的例程、调用malloc()函数或者其他返回了一个你需要负责释放的内存缓冲区的系统调用? - Jason Coco
5个回答

7

有一个快速的尝试方法是运行Clang静态分析器。这将找到您代码中可能会遗漏的一些问题,但不是全部。它在编译时检查代码,因此并非绝对可靠,但几乎肯定会发现大多数显著问题。


+1 给 Clang。它找到了我错过的许多内存泄漏。这是一个教程,当我在努力设置时起作用:http://www.oiledmachine.com/posts/2009/01/06/using-the-llvm-clang-static-analyzer-for-iphone-apps.html - bbrown

4

您还应该使用内存监视器工具来运行应用程序,以查看设备上的系统整体使用情况。


抱歉,如果原始问题不够清晰,但我也尝试过了。这就是告诉我网络使用量在600-700k字节范围内的原因。而且我可以在那个工具中看到所有对象都被清理了。 - Bdebeez
刚才那个评论请忽略 - 我一直在使用ObjectAlloc。非常感谢您的提示 - 内存监视器确实显示我正在使用大量内存。现在我需要找出原因是什么... - Bdebeez
仅因为您没有创建自己的基础对象并不意味着它们不会因诸如NSArray或NSURLConnection之类的事物而为您创建。 - wisequark

2

泄漏只会发现未被任何引用但仍保留的内存。

你所看到的是,你留下了保留的内存,并且仍然被某些东西引用。

特别要注意的一件事是,如果你将类的引用作为委托传递给其他内容,那么在dealloc方法中释放它。

同样地,如果你订阅了任何通知,你应该在viewWillDisappear:中取消订阅(如果你在视图控制器中使用通用取消订阅方法,则不要忘记重新订阅内存警告通知)。

定时器也是如此,在视图消失时停用它们,在视图返回时重新启用它们(当然,如果你需要一个在整个应用程序运行期间都运行的定时器,则除外)。

基本上,对于任何你给予类的引用,都要持怀疑态度,并尽可能找出如何消除该链接(无论是在dealloc还是viewWillDisappear:中或两者都有)。


2
以下是我学到的一些总结(感谢一些优秀的答案和评论):
- 对象分配并不等同于内存使用。关于ObjectAlloc的净字节元素的问题,答案是你不应该关注它——至少在确定你使用的内存量或导致应用程序崩溃的原因时不应该关注它。它不反映您应用程序的真实内存使用情况。 - 我的业余猜测是,ObjectAlloc只显示直接对象本身占用的内存。所以如果你有一个UIImageView,它只需要占用一些字节来存储各种属性,但它可能指向一个在内存中占用大量空间的图像。因此,仅查看ObjectAlloc有助于确保您不会创建和保留对象,它不会给您一个关于您使用了多少内存或在崩溃之前可以使用多少内存的想法。 - MemoryMonitor将为您提供总内存使用情况。您可以使用Instruments窗口底部的搜索工具将其限制为仅查看您的应用程序使用情况。 - ObjectAlloc和Memory Monitor(以及Leaks工具)都是Instruments的插件——以防这对其他人不明显。您可以通过运行->启动性能工具从XCode中启动Instruments。一旦进入Instruments,您就可以打开库并添加新的插件来监视性能的不同方面。

太好了。这是意味着你已经解决了它吗?还是它仍在运行中? - philsquared
还是有一个bug :( 我在这里提了一个更具体的问题 - https://dev59.com/hHVC5IYBdhLWcg3wcwwm - Bdebeez
我已经修复了我的特定错误 - 上述URL包含了解决方案。 - Bdebeez

0

要注意的一件事是循环引用。

(我不想让这听起来很自以为是 - 只是想确保我讲得清楚 :) 如果对象 a 引用对象 b,而对象 b 又引用对象 a,可能不会报告“泄漏”,因为所有内存仍然被引用 - 但这可能是一个孤立的对象岛屿,与您的应用程序分离并且永远无法回收。当然,它可能涉及更多对象(例如,a 引用 bb 引用 cc 又引用 a,等等)。

如果您在某个地方构建了对象图,并且存在任何反向或交叉引用,请确保在释放根后打破循环引用(有不同的方法可以做到这一点。最简单的方法可能是确保每个相关类都有一个 releaseAll 方法或类似方法 - 它会调用其子对象的 releaseAll 方法,然后释放子对象 - 但这并不总是最好的解决方案)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接