我将一些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可以随时收集,还是仅在特定时间收集,例如运行循环结束?没有设法找到相关的文档。
答案 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指出的那样,即使你的函数在主线程中,垃圾收集器也可以在你的函数中运行。