无法访问的对象在无法访问后的任何时间都是安全的吗?

时间:2011-04-29 17:31:24

标签: objective-c cocoa garbage-collection objective-c++

我将一些Obj-C对象存储在C ++数据结构中。因为我在垃圾收集下运行而且我的对象只能通过C ++结构访问,所以我调用CFRetain()来根据添加到结构中的每个对象来确保它们不会过早收集:

- (void) doSomethingFancyWithObjects:(NSArray*)array
{
    std::list<NSObject*> list;

    for (NSObject* obj in array)
    {
        id copyAddedToList = [obj copy];
        list.push_back(copyAddedToList);
        CFRetain(copyAddedToList); // otherwise list.back() becomes unreachable...
    }

    // ... //

    BOOST_FOREACH(NSObject* obj, list)
    {
        CFRelease(obj);
    }
}

有必要这样做吗? GC是否有可能在无法访问的方法中启动并收集无法访问的对象? GC可以随时收集,还是仅在特定时间收集,例如运行循环结束?没有设法找到相关的文档。

2 个答案:

答案 0 :(得分:1)

在您的代码中发布的所有事情都发生在doSomethingFancyWithObjects:范围内,您不需要CFRetain/CFRelease对,因为您没有从堆栈中的array中删除对象因此扎根。

修改

好的,我没有正确阅读代码 - 正在复制对象。

首先,我会质疑复制的必要性。如果要修改列表中的对象,为什么?最后他们被扔掉了。

其次,你实际上有一个竞争条件。垃圾收集器可以介于list.push_back([obj copy]);CFRetain(list.back());之间,然后std::list中的对象指针将悬空。你应该做点什么:

NSObject* theCopy = [obj copy];
CFRetain(theCopy);
list.push_back(theCopy);

答案 1 :(得分:0)

我在这里找到了一些信息:

Garbage Collection Programming Guide

  

在标准应用程序中,Cocoa会自动提示事件周期中合适的点,该集合可能是合适的。如果内存负载超过阈值,则收集器将启动收集。通常,这应该足以提供良好的性能。但是,有时您可能会向收集器提供可能需要保证集合的提示 - 例如,在创建大量临时对象的循环之后。您可以使用NSGarbageCollector方法collectIfNeeded。

执行此操作

这似乎表明垃圾收集器不会在函数中间(或同时从另一个线程!)神奇地运行,而只是在事件周期的某个地方运行。

你是对的,一般来说,如果你不希望它们被垃圾收集在你身上,那么保留c ++中的对象是很重要的,正如文档中所述:

  

通常,C ++代码应保持不变:您可以假设从标准malloc区域分配内存。如果您需要确保Objective-C对象的寿命,您应该使用CFRetain而不是保留。

修改

糟糕,我发现了illuminating part更多参考文献:

  

收集器是请求和需求驱动的。 Cocoa实现在适当的时候发出请求。您还可以以编程方式请求考虑垃圾回收周期,如果超出内存阈值,则会自动运行收集。

     

收集器在应用程序中的自己的线程上运行。

正如Jeremy指出的那样,即使你的函数在主线程中,垃圾收集器也可以在你的函数中运行。