关于ios:Objective-C中的自动引用计数不会阻止或最小化哪种泄漏?

What kind of leaks does automatic reference counting in Objective-C not prevent or minimize?

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

Xcode4.2附带的工具链引入了最新版本的LLVM编译器的自动引用计数(ARC),通过让编译器为您内存管理您的东西,完全解决了这个问题。这很酷,它确实缩短了许多不必要的、平凡的开发时间,并防止了许多不小心的内存泄漏,这些泄漏很容易通过适当的保留/释放平衡来修复。当您为Mac和iOS应用程序启用ARC时,甚至自动租赁池也需要以不同的方式进行管理(因为您不应该再分配自己的NSAutoreleasePool)。

但是,还有什么记忆泄漏,它不能阻止我仍然要注意的?

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


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

因此,存在__unsafe_unretained__weak所有权限定符。前者不会保留它指向的任何对象,但会使该对象离开并指向坏内存的可能性打开,而后者不会保留该对象,并在解除分配目标时自动将其自身设置为零。其中,__weak在支持它的平台上通常是首选的。

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

另一个重要的内存相关问题是使用EDCOX1(3)来处理核心基础对象和内存分配,如EDCOX1(4)。ARC不管理这些类型,只管理Objective-C对象,因此您仍然需要自己处理它们。核心基础类型可能特别棘手,因为有时它们需要桥接到匹配Objto-C对象,反之亦然。这意味着在CF类型和Objective-C之间进行桥接时,需要从ARC来回传输控制。添加了与此桥接相关的一些关键字,Mike Ash在其冗长的ARC撰写中对各种桥接案例进行了很好的描述。

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

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

ARC只是简单地接受多年来我们必须完成的重复内存管理任务,然后将它们卸载到编译器中,这样我们就不再需要担心它们了。这样,您就没有垃圾收集平台上遇到的暂停问题或锯齿状内存配置文件。我在我的垃圾收集的Mac应用程序中都经历过这两种情况,并且渴望看到它们在ARC下的行为。

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


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

如果编译器无法确定选择器是什么(编译器将对此生成警告),则performSelector:可能会愚弄ARC。

ARC还将生成遵循objc命名约定的代码,因此,如果将ARC和MRC代码混合使用,那么如果MRC代码没有按照编译器认为的名称所承诺的方式执行,则会得到令人惊讶的结果。


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

  • 在解除视图控制器时不使nstimers无效
  • 在解除视图控制器时,忘记将任何观察器删除到nsnotificationcenter。
  • 在块中保持对自身的强引用。
  • 在视图控制器属性中使用对委托的强引用
  • 幸运的是,我看到了以下博客文章,并能够纠正它们:http://www.revisdesign.com/blog/debugging-retain-cycles-in-objective-c-four-liked-criprits/


    Xcode9为发现此类问题提供了一个很好的工具。它被称为"调试内存图"。使用它,您可以按类类型找到泄漏的对象,并且可以清楚地看到谁持有对它的强引用,从中释放它可以解决您的问题。它还检测内存循环。

    查看有关如何使用它的详细信息


    ARC也不会管理CoreFoundation类型。您可以"桥接"它们(使用CFBridgingRelease()),但前提是您要将其用作objective-c/cocoa对象。请注意,cfbridgingrelease只是将corefoundation保留计数减少1,并将其移动到objective-c的arc。