【发布时间】:2010-09-15 09:17:25
【问题描述】:
发生内存(和资源)泄漏。你如何确保他们没有?
您会建议哪些技巧和技术来帮助避免首先造成内存泄漏?
一旦您的应用程序发生泄漏,您如何追踪泄漏源?
(哦,请避免“只使用 GC”的答案。在 iPhone 支持 GC 之前,这不是一个有效的答案,即使那样 - 可能会在 GC 上泄漏资源和内存)
【问题讨论】:
标签: objective-c cocoa debugging macos memory
发生内存(和资源)泄漏。你如何确保他们没有?
您会建议哪些技巧和技术来帮助避免首先造成内存泄漏?
一旦您的应用程序发生泄漏,您如何追踪泄漏源?
(哦,请避免“只使用 GC”的答案。在 iPhone 支持 GC 之前,这不是一个有效的答案,即使那样 - 可能会在 GC 上泄漏资源和内存)
【问题讨论】:
标签: objective-c cocoa debugging macos memory
遵循保留和释放规则(或使用垃圾收集)。 They're summarized here.
使用仪器追踪泄漏。您可以使用 Xcode 中的 Build > Start With Performance Tool 在 Instruments 下运行应用程序。
【讨论】:
Instruments Leaks 工具非常擅长发现某种类型的内存泄漏。只需使用“Start with Performance Tool”/“Leaks”菜单项即可通过此工具自动运行您的应用程序。适用于 Mac OS X 和 iPhone(模拟器或设备)。
Leaks 工具可帮助您找到泄漏源,但对追踪泄漏内存的保留位置没有太大帮助。
【讨论】:
我记得不久前我使用 Omni 的一个工具,当时我试图追踪一些内存泄漏,这些泄漏会显示对象上的所有保留/释放/自动释放调用。我认为它显示了分配的堆栈跟踪以及对象上的所有保留和释放。
【讨论】:
在 XCode 4.5 中,使用内置的Static Analyzer。
在 3.3 之前的 XCode 版本中,您可能需要下载静态分析器。这些链接向您展示了如何:
为避免一开始就造成内存泄漏,请使用Clang Static Analyzer -- 不出所料 -- 在 Mac OS X 10.5 上分析您的 C 和 Objective-C 代码(还没有 C++)。安装使用很简单:
cd 到您的项目目录。scan-build -k -V xcodebuild。(还有一些额外的限制等,特别是您应该在其“调试”配置中分析一个项目——有关详细信息,请参阅http://clang.llvm.org/StaticAnalysisUsage.html——但这或多或少是归结为的。)
分析器随后会为您生成一组网页,其中显示可能的内存管理和编译器无法检测到的其他基本问题。
如果您的项目不针对 Mac OS X 桌面,还有一些其他细节:
(这与this question 的答案基本相同。)
【讨论】:
如果您总是使用访问器方法为实例变量赋值(init* 和 dealloc 方法除外),那么您自己的生活就会变得更加简单。除了确保正确触发任何副作用(例如KVO change notifications)之外,与使用@987654325 撒上代码相比,它使您遭受复制粘贴或其他一些逻辑错误的可能性要小得多@s 和releases。
在声明访问器时,您应该始终使用Objective-C 2 properties 功能。属性声明使访问器的内存管理语义明确。它们还为您提供了一种简单的方法来交叉检查您的 dealloc 方法,以确保您已释放您声明为 retain 或 copy 的所有属性。
【讨论】:
出于某种原因,许多开发人员(尤其是早期开发人员)使自己的内存管理比以往任何时候都更加困难,通常是通过过度思考问题或想象问题比实际情况更复杂。
fundamental rules 非常简单。您应该只专注于遵循这些。不要担心其他对象可能会做什么,或者您的对象的保留计数是多少。相信其他人都遵守相同的合同,这一切都会正常工作。
特别是,我将重申不要担心对象的保留计数这一点。由于各种原因,保留计数本身可能会产生误导。如果您发现自己记录了对象的保留计数,则几乎可以肯定您走错了路。退一步问问自己,你是否遵守基本规则?
【讨论】:
首先,您对 [ ] 和 { } 括号和大括号的使用符合通用标准非常重要。好吧,开个玩笑。
查看泄漏时,您可以假设泄漏是由于代码中的问题造成的,但这并不是 100% 的错误。在某些情况下,Apple 的(喘气!)代码中可能发生了错误。而且它可能很难找到,因为它不会显示为被分配的可可对象。我过去曾向 Apple 报告过泄漏错误。
泄漏有时很难找到,因为您发现的线索(例如,数百个字符串泄漏)可能不是因为直接导致字符串泄漏的那些对象正在泄漏,而是因为某些东西正在泄漏 那个 对象。通常,您必须挖掘泄漏的“树”的叶子和树枝才能找到问题的“根源”。
预防:我的主要规则之一是真的,真的,真的避免分配一个对象,而不是当场自动释放它。任何你分配/初始化一个对象然后在代码块中释放它的地方都是你犯错的机会。要么你忘记释放它,要么你抛出一个异常以使释放永远不会被调用,或者你在方法的某处放置一个“return”语句以提前退出(我也尽量避免)。
【讨论】:
您可以从这里构建 Valgrind 的 beta 端口:http://www.sealiesoftware.com/valgrind/
它比任何静态分析都有用得多,但据我所知,它还没有任何特殊的 Cocoa 支持。
【讨论】:
显然,您首先需要了解基本的内存管理概念。但在追查泄漏方面,我强烈建议阅读this tutorial on using the Leaks mode in Instruments。
【讨论】: