在Mac和iOS平台上,内存泄漏通常是由未释放的指针引起的。传统上,检查您的分配、副本和保留以确保每个都有相应的发布消息一直是极其重要的。

The toolchain that comes with Xcode 4.2 introduces automatic reference counting (ARC) with the latest version of the LLVM compiler, that totally does away with this problem by getting the compiler to memory-manage your stuff for you. That's pretty cool, and it does cut lots of unnecessary, mundane development time and prevent a lot of careless memory leaks that are easy to fix with proper retain/release balance. Even autorelease pools need to be managed differently when you enable ARC for your Mac and iOS apps (as you shouldn't allocate your own NSAutoreleasePools anymore).

但是,还有哪些内存泄漏是我仍然需要注意的呢?

另外,Mac OS X和iOS上的ARC和Mac OS X上的垃圾收集有什么不同?


当前回答

Xcode 9提供了一个很好的工具来发现这类问题。它被称为:“调试内存图”。 使用它,你可以通过类类型找到泄露的对象,你可以清楚地看到谁持有对它的强引用,通过从那里释放它解决了你的问题。它还可以检测内存周期。

请参阅有关如何使用它的更多信息

其他回答

您仍然需要注意的与内存相关的主要问题是保留周期。当一个对象有指向另一个对象的强指针,而目标对象有指向原始对象的强指针时,就会发生这种情况。即使删除了对这些对象的所有其他引用,它们仍然会彼此保留,不会被释放。这也可以间接发生,通过一个对象链,链中的最后一个对象可能引用回一个较早的对象。

正是由于这个原因,才存在__unsafe_unretained和__weak所有权限定符。前者不会保留它所指向的任何对象,但保留了该对象消失并指向坏内存的可能性,而后者不保留对象,并在其目标被释放时自动将自己设置为nil。在这两者中,__weak通常是支持它的平台的首选。

您可以将这些限定符用于委托之类的事情,其中您不希望对象保留其委托并可能导致循环。

Another couple of significant memory-related concerns are the handling of Core Foundation objects and memory allocated using malloc() for types like char*. ARC does not manage these types, only Objective-C objects, so you'll still need to deal with them yourself. Core Foundation types can be particularly tricky, because sometimes they need to be bridged across to matching Objective-C objects, and vice versa. This means that control needs to be transferred back and forth from ARC when bridging between CF types and Objective-C. Some keywords related to this bridging have been added, and Mike Ash has a great description of various bridging cases in his lengthy ARC writeup.

除此之外,还有其他一些不太常见但仍有潜在问题的情况,已发布的规范详细介绍了这些情况。

很多新的行为都是基于只要有强指针指向对象,就会保留对象,这与Mac上的垃圾收集非常相似。然而,技术基础非常不同。这种风格的内存管理依赖于我们在Objective-C中都需要遵守的严格的保留/释放规则,而不是有一个定期运行的垃圾收集器进程来清理不再被指向的对象。

ARC只是把我们多年来不得不做的重复内存管理任务卸载给编译器,这样我们就再也不用担心它们了。这样,您就不会遇到在垃圾收集平台上遇到的停止问题或锯齿状内存配置文件。我在我的垃圾收集Mac应用程序中经历过这两种情况,我渴望看到它们在ARC下的表现。

关于垃圾收集与ARC的更多信息,请参阅Chris Lattner在Objective-C邮件列表上的这篇非常有趣的回复,在那里他列出了ARC相对于Objective-C 2.0垃圾收集的许多优点。我遇到过他描述的几个GC问题。

ARC不会帮助你使用非objc内存,例如,如果你malloc()一些东西,你仍然需要free()它。

ARC可以被performSelector欺骗:如果编译器不能找出选择器是什么(编译器将生成一个警告)。

ARC也会生成遵循ObjC命名约定的代码,所以如果你把ARC和MRC代码混合在一起,如果MRC代码没有做编译器认为名称承诺的事情,你会得到令人惊讶的结果。

Xcode 9提供了一个很好的工具来发现这类问题。它被称为:“调试内存图”。 使用它,你可以通过类类型找到泄露的对象,你可以清楚地看到谁持有对它的强引用,通过从那里释放它解决了你的问题。它还可以检测内存周期。

请参阅有关如何使用它的更多信息

ARC也不会管理CoreFoundation类型。你可以“桥接”它们(使用CFBridgingRelease()),但前提是你要把它用作Objective-C/Cocoa对象。注意CFBridgingRelease只是将CoreFoundation保留计数减1,并将其移动到Objective-C的ARC中。

由于以下4个问题,我在我的应用程序中遇到了内存泄漏:

在解散视图控制器时不使NSTimers无效 当解散视图控制器时忘记删除NSNotificationCenter的任何观察者。 在块中保持对self的强引用。 在视图控制器属性中使用对委托的强引用

幸运的是,我看到了下面的博客文章,并能够纠正它们:http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/