Objective-C中的自动引用计数不会阻止或减少哪种泄漏?


235

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

Xcode 4.2随附的工具链在最新版本的LLVM编译器中引入了自动引用计数(ARC),通过使编译器为您的内容进行内存管理,从而完全解决了此问题。这很酷,并且确实减少了很多不必要的,平凡的开发时间,并防止了许多粗心大意的内存泄漏,这些泄漏很容易通过适当的保留/释放平衡来解决。当为Mac和iOS应用程序启用ARC时,甚至需要对自动释放池进行不同的管理(因为您NSAutoreleasePool不再应该分配自己的s)。

但是,其他的内存泄漏它不能阻止我仍然要注意?

另外,Mac OS X和iOS上的ARC与Mac OS X上的垃圾回收之间有什么区别?

Answers:


262

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

正是由于这个原因,存在__unsafe_unretained__weak所有权限定词。前者将不会保留其指向的任何对象,但会留出该对象消失并指向内存不足的可能性,而后者不会保留该对象,并在释放目标时自动将其自身设置为nil。在这两者之间,__weak在支持它的平台上通常是首选。

您可以将这些限定符用于诸如委托之类的事情,在这种情况下,您不希望对象保留其委托并可能导致周期。

与内存相关的另外两个重要问题是对Core Foundation对象的处理以及malloc()为这类分配的内存char*。ARC不管理这些类型,仅管理Objective-C对象,因此您仍然需要自己处理它们。核心基础类型可能特别棘手,因为有时需要将它们跨接至匹配的Objective-C对象,反之亦然。这意味着在CF类型和Objective-C之间桥接时,需要从ARC来回传递控制。添加了与此桥接相关的一些关键字,Mike Ash在其冗长的ARC文章中对各种桥接情况进行了很好的描述。

除此之外,还有其他一些较不常见但仍存在问题的案例,已发布的规范对此进行了详细介绍。

许多新的行为都是基于只要有强大的指针就能保持对象周围,这与Mac上的垃圾收集非常相似。但是,技术基础非常不同。这种内存管理方式不是使垃圾回收器进程定期运行以清理不再指向的对象,而是依靠我们都需要在Objective-C中遵守的严格保留/释放规则。

ARC只是简单地承担了我们多年以来重复执行的内存管理任务,并将其卸载到编译器中,因此我们不必再为它们担心。这样,您就不会遇到在垃圾收集平台上遇到的停止问题或锯齿状内存配置文件的情况。我在垃圾回收的Mac应用程序中都经历了这两种情况,并渴望了解它们在ARC下的行为。

有关垃圾回收与ARC的更多信息,请参阅Chris Lattner在Objective-C邮件列表上的非常有趣的回复,他在其中列出了ARC与Objective-C 2.0垃圾回收相比的许多优点。我遇到了他描述的一些GC问题。


2
感谢您的详细回答。我遇到了同样的问题,我在_unsafe_unretained下定义了一个委托,并使我的应用程序崩溃了,后来通过更改为Strong来修复了它,但是现在它存在内存泄漏。因此,我将其更改为弱项,并且像魅力一样工作。
chathuram

@ichathura哇!您将我从ARC泥潭中救了出来。使用CMPopTipView时遇到了相同的崩溃。
Nianliang

@BradLarson:“您不会遇到在垃圾收集平台上遇到的停顿问题或锯齿状内存配置文件”。我希望基于作用域的回收会导致停止和锯齿内存配置文件恶化,而引用计数会导致性能下降,所以我希望看到一个真正的比较。
乔恩·哈罗普

布拉德,克里斯·拉特纳(Chris Lattner)的联系已死。我不是100%,但是我找到了另一个链接。我认为这是你想要的链接到:lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/...
蜂蜜

1
@Honey-感谢您指出这一点。您链接的链接略有不同,但是我用原始消息的存档版本替换了无效链接。它在邮件列表档案中,应该在某处可用,但是我将看看是否可以找到它们的新位置。
布拉德·拉尔森

14

ARC不能为您提供非ObjC内存,例如,如果您malloc()需要某些东西,仍然需要free()它。

performSelector:如果编译器无法弄清楚选择器是什么,则ARC会被愚弄(编译器将对此发出警告)。

ARC还将遵循ObjC命名约定生成代码,因此,如果将ARC和MRC代码混合使用,则如果MRC代码不执行编译器认为的名称承诺,您将得到令人惊讶的结果。



0

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


0

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

查看有关如何使用它的更多信息

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.