Are unreachable objects safe from collection for any time after becoming unreachable?
I'm storing some Obj-C objects in a C++ data structure. Since I'm running under garbage collection and my objects are only reachable via the C++ structure, I'm calling CFRetain() to root each object added to the structure to ensure they aren't collected prematurely:
- (void) doSomethingFancyWithObjects:(NSArray*)array
{
std::list&开发者_高级运维lt;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);
}
}
Is it necessary to do this? Is there actually any chance that the GC will kick in and collect unreachable objects during the method in which they become unreachable? Can the GC collect at any time, or only at specific times such as the end of the run loop? Haven't managed to find a relevant bit of documentation on this.
As posted in your code in which everything happens within the scope of doSomethingFancyWithObjects:
you do not need the CFRetain/CFRelease
pair because you are not removing the objects from array
which is on the stack and therefore rooted.
Edit
OK, I didn't read the code properly - the objects are being copied.
Firstly, I would question the need for copying. If you are modifying the objects in the list, why? They are being thrown away at the end.
Secondly, you actually have a race condition. The garbage collector could get in between list.push_back([obj copy]);
and CFRetain(list.back());
and then the object pointer in the std::list
will be dangling. You should do something like:
NSObject* theCopy = [obj copy];
CFRetain(theCopy);
list.push_back(theCopy);
I found some info here:
Garbage Collection Programming Guide
In a standard application, Cocoa automatically hints at a suitable point in the event cycle that collection may be appropriate. The collector then initiates collection if memory load exceeds a threshold. Typically this should be sufficient to provide good performance. Sometimes, however, you may provide a hint to the collector that collection may be warranted—for example after a loop in which you create a large number of temporary objects. You can do this using the NSGarbageCollector method collectIfNeeded.
This seems to indicate that the garbage collector won't be run magically in the middle of functions (or simultaneously from another thread!), but only somewhere in the event cycle.
You're right, though, that in general it's important to retain objects in c++ if you don't want them to be garbage collected out from under you as is also stated in the document:
In general, C++ code should remain unchanged: you can assume memory allocated from standard malloc zone. If you need to ensure the longevity of Objective-C objects, you should use CFRetain instead of retain.
EDIT
Oops, I discovered this more illuminating part of the reference:
The collector is both request and demand driven. The Cocoa implementation makes requests at appropriate times. You can also programmatically request consideration of a garbage collection cycle, and if a memory threshold has been exceeded a collection is run automatically.
The collector runs on its own thread in the application.
So as Jeremy points out, the garbage collector can run in the middle of your function even if your function is in the main thread.
精彩评论