除非在后台线程中获取新的引用,否则潜在的引用计数问题

Posted

技术标签:

【中文标题】除非在后台线程中获取新的引用,否则潜在的引用计数问题【英文标题】:Potential reference count issues unless grabbing fresh reference in background thread 【发布时间】:2015-03-06 20:15:19 【问题描述】:

如果可以的话,在阅读 Marcus S. Zarra 的(优秀)Core Data: Data Storage and Management for ios, OS X, and iCloud(第二版)后,我有一个second 的问题。

本书的异步添加 NSPersistentStore 部分包含这段代码(摘录):

dispatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^

    // ...

    NSPersistentStoreCoordinator *coordinator = nil;
    coordinator = [[self managedObjectContext] persistentStoreCoordinator];

    // ...
);

它还包含这样的解释:

我们获取新参考的原因 NSPersistentStoreCoordinator 是一种安全。如果我们使用 来自外部方法的引用,我们将增加保留 NSPersistentStoreCoordinator 的计数并可能导致 不必要的引用计数问题。

这个潜在的引用计数问题的性质是什么?

我知道,如果调度的块将引用范围外的NSPersistentStoreCoordinator,它将保留该协调器(将其引用计数增加一),然后只有在块完成执行后才能释放该协调器。如果后台线程从未执行过或者它不会终止,那么引用计数问题将仍然存在。

仅此而已,还是有更微妙的情况也会构成引用计数问题并且可能在这种情况下实现?

就目前而言,我不会(非常)担心这种特殊情况下的潜在引用计数问题(为立即执行而调度的简单后台操作),但也许我遗漏了一些东西。

【问题讨论】:

【参考方案1】:

在此示例中,块本身可能执行得相对较晚(许多其他代码可以在此块之前执行)。这意味着上下文或存储协调器可能会发生很多事情,并且假设存储协调器在块开始执行之前和之后甚至不是同一个对象。

通过调用管理器来检索协调器的新引用,您首先确保您将获得最新的协调器,并且您不会保留当前的协调器。如果您要从块外部重用协调器,该协调器将被保留并可能产生(尽管不太可能)问题,例如内存膨胀。如果一切都变糟了,甚至从未执行过该块,那么协调器就会被永远保留,并且您会出现内存泄漏。

这只是一个好习惯。

【讨论】:

所以我猜它“提防引用计数问题的开始”。

以上是关于除非在后台线程中获取新的引用,否则潜在的引用计数问题的主要内容,如果未能解决你的问题,请参考以下文章

内存映射文件类、线程和引用计数

常用GC算法

如何查看变量的引用计数?

引用计数

「JVM基础」——垃圾回收基础(GC相关)

HTTP状态码