Avoiding, finding and removing memory leaks in Cocoa
发生内存(和资源)泄漏。你如何确保他们没有?
您会建议哪些技巧和技术来帮助避免在第一时间造成内存泄漏?
一旦您有一个正在泄漏的应用程序,如何跟踪泄漏源?
(哦,请避免"只使用gc"的答案。在iPhone支持GC之前,这不是一个有效的答案,即使是这样,也有可能泄漏GC上的资源和内存)
在Xcode4.5中,使用内置的静态分析器。
在3.3之前的Xcode版本中,您可能需要下载静态分析器。这些链接向您展示了如何:
使用llvm/clang静态分析器为了避免首先产生内存泄漏,使用CLAN静态分析器——毫不奇怪——在Mac OS X 10.5上分析C和Objul-C代码(没有C++)。安装和使用很简单:
(还有一些附加的约束等,特别是您应该在"调试"配置中分析一个项目——有关详细信息,请参阅http://clang.llvm.org/staticanalysiususage.html——但这或多或少就是它的归宿。)
然后分析器为您生成一组网页,显示可能的内存管理和编译器无法检测到的其他基本问题。
如果您的项目不以Mac OS X桌面为目标,则还有一些其他详细信息:
(这在很大程度上与这个问题的答案相同。)
不要过度考虑内存管理
出于某种原因,许多开发人员(特别是早期的开发人员)经常通过过度考虑问题或想象问题比实际情况更复杂,使内存管理变得比实际情况更困难。
基本规则非常简单。你应该专注于跟随这些。不要担心其他对象可能会做什么,或者对象的保留计数是多少。相信其他人都遵守同一份合同,这一切都会奏效的。
特别是,我要重申一点,即不要担心对象的保留计数。保留计数本身可能因各种原因而误导。如果您发现自己记录了一个对象的保留计数,那么您几乎肯定是走错了方向。退一步问问自己,你是否遵守了基本规则?
始终使用访问器方法;使用属性声明访问器
如果总是使用访问器方法为实例变量赋值(
声明访问器时,应始终使用Objective-C2属性功能。属性声明使访问器的内存管理语义显式化。它们还为您提供了一种简单的方法来交叉检查您的
InstrumentsLeaks工具非常擅长查找某类内存泄漏。只需使用"StartWithPerformanceTool"/"Leaks"菜单项,即可通过此工具自动运行应用程序。适用于Mac OS X和iPhone(模拟器或设备)。
Leaks工具可以帮助您找到泄漏源,但对跟踪泄漏内存的保留位置没有太大帮助。
遵循保留和释放(或使用垃圾收集)的规则。总结如下。
使用仪器跟踪泄漏。您可以使用xcode中的build>start with performance工具在instruments下运行应用程序。
我记得有一段时间我使用了Omni的一个工具,当时我试图跟踪一些内存泄漏,这些泄漏会显示对一个对象的所有retain/release/autorelease调用。我认为它显示了分配的堆栈跟踪以及对象上的所有保留和释放。
http://www.omnigroup.com/developer/omniobjectmeter/
您可以从这里构建Valgrind的测试端口:http://www.sealiesoftware.com/valgrind/
它远比任何静态分析都有用,但我还不知道它有什么特殊的可可支持。
首先,重要的是,您使用的[]和括号和大括号符合通用标准。好吧,开玩笑吧。
在查看泄漏时,可以假定泄漏是由代码中的问题造成的,但这并不是100%的故障。在某些情况下,苹果公司可能发生了一些事情(喘息!)有故障的代码。这可能是很难找到的,因为它不会显示为分配的可可对象。我以前向苹果公司报告过漏洞。
有时很难找到泄漏,因为您发现的线索(例如,数百个字符串泄漏)可能发生,而不是因为那些直接负责字符串的对象泄漏,而是因为有东西泄漏了该对象。为了找到问题的"根源",你常常需要挖掘泄漏的"树"的叶子和树枝。
预防:我的一个主要规则是真正地,真正地,真正地避免分配一个对象,而不只是当场自动重新分配它。任何你分配/初始化一个对象,然后在代码块中释放它的地方,都是你犯错误的机会。要么你忘记释放它,要么你抛出了一个异常,这样释放就永远不会被调用,要么你在方法的某个地方放置了一个"return"语句,用于提前退出(我也试图避免这种情况)。
显然,您首先需要了解基本的内存管理概念。但在追查泄漏方面,我强烈建议您阅读本教程,了解如何在仪器中使用泄漏模式。