无法访问的对象在无法访问后无法安全收集?
我在C++数据结构中存储了一些Obj-C对象。由于我的垃圾收集下运行,我的对象只能通过C++结构可到达,我打电话CFRetain()以root每个对象添加到结构,以确保它们不会过早地收集:无法访问的对象在无法访问后无法安全收集?
- (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是否可以在任何时间收集,或只在特定的时间收集,如运行循环结束?还没有设法找到这方面的相关文件。
我发现了一些信息在这里:
Garbage Collection Programming Guide
在一个标准的应用,可可自动在活动周期该集合可适当一个合适的点提示。如果内存负载超过阈值,收集器将启动收集。通常这应该足以提供良好的性能。然而,有时候,您可能会向收集器提供一个提示,说明收集可能是有保证的 - 例如,在创建大量临时对象的循环之后。您可以使用NSGarbageCollector方法collectIfNeeded来完成此操作。
这似乎表明垃圾收集器不会在函数中间(或者从另一个线程同时发生)奇迹般地运行,而只是在事件周期的某个地方运行。
你是对的,不过,在总体上保持在C对象++,如果你不希望他们是从下你收集了垃圾如该文件中还指出很重要:
一般来说,C++代码应该保持不变:您可以假定从标准malloc区域分配内存。如果您需要确保Objective-C对象的使用寿命,则应该使用CFRetain而不是retain。
EDIT
糟糕,我发现了参考的这种更illuminating part:
集电极是包括请求和需求的驱动。 Cocoa实现在适当的时候发出请求。您也可以编程方式请求考虑垃圾回收周期,并且如果超过了内存阈值,则会自动运行集合。
收集器在应用程序中的其自己的线程上运行。
正如Jeremy指出的那样,即使您的函数位于主线程中,垃圾收集器也可以在函数的中间运行。
由于您的代码中发布的一切都发生在doSomethingFancyWithObjects:
的范围内,因此您不需要CFRetain/CFRelease
对,因为您并未从堆栈中的array
中删除对象并因此生根。
编辑
OK,我没有正确读取编码 - 对象被复制。
首先,我会质疑需要复制。如果您正在修改列表中的对象,为什么?最后他们被抛弃。
其次,你实际上有一个竞争条件。垃圾收集器可能在list.push_back([obj copy]);
和CFRetain(list.back());
之间,然后std::list
中的对象指针将悬空。你应该这样做:
NSObject* theCopy = [obj copy];
CFRetain(theCopy);
list.push_back(theCopy);
好的地方,没有注意到你引用的第一段。但是,苹果仍然使用“事件循环”来引用主线程的运行循环,所以如果这就是他们的意思,我只能在主线程上运行时保证这种保证(不幸的是,我不是。 ..) – 2011-05-02 19:16:32
哦,你的函数在另一个线程中运行?看起来你应该这样做CFRetain。与所有其他花哨的东西相比,这可能不是什么大事! – 2011-05-03 01:29:27
垃圾收集器在其自己的线程中运行,只要感觉需要GC就会运行。你不能认为它没有在任何一个特定的功能中运行。 – JeremyP 2011-05-09 15:06:31