Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does ARC guarantee that an object is dealloc'ed instantly once the last strong reference is gone?

In particular, would this kind of code always work as intended (where MyResourceGuard is an object that locks an exclusive resource in its init method and frees the lock in its dealloc method):

NSLog(@"About to capture some exclusive resource.");
{
  MyResourceGuard* guard = [MyResourceGuard new];
  // Do something with the exclusive resource here.
}
// guard is out of scope, therefore its dealloc should have
// been called right away and the resource should already
// be free again at this point.

I have read in books and blogs that in contrast to e.g. Java garbage collection, ARC destroys objects as soon as the reference count decreases to zero (and not at some time of its own convenience), but I haven't read this in any official documentation by Apple. And if that were true, why would we ever need the new @autoreleasepool keyword introduced with ARC?

From debugging, I have always seen the object dealloc'ed immediately, except when an exception is raised in a try-catch-block, in which case dealloc actually was never called (is that a Mac bug, or just one of these scary Objective C oddities?).

like image 313
Andreas Zollmann Avatar asked Nov 16 '12 13:11

Andreas Zollmann


People also ask

How does ARC work in Objective C and how is it different from garbage collection?

ARC differs from tracing garbage collection in that there is no background process that deallocates the objects asynchronously at runtime. Unlike tracing garbage collection, ARC does not handle reference cycles automatically.

Does Objective C support Arc?

Automatic Reference Counting (ARC) is a memory management option for Objective-C provided by the Clang compiler. When compiling Objective-C code with ARC enabled, the compiler will effectively retain, release, or autorelease where appropriate to ensure the object's lifetime extends through, at least, its last use.

How do you call Dealloc in Objective C?

dealloc is called as a result of memory management. Once an objects "retainCount" reaches 0 then a dealloc message is automatically sent to that object. You should never call dealloc on objects unless it is a call to [super dealloc]; at the end of an overridden dealloc. You never send a dealloc message directly.


1 Answers

No. You don't have deterministic scope based destruction of ObjC objects as your example shows.

For example, this program could result in deadlock:

{ MyResourceGuard* guard = [MyResourceGuard new]; }
{ MyResourceGuard* guard = [MyResourceGuard new]; }

The best you can do if you need this functionality is to use C++ types (SBRM, RAII) -- also available in Objective-C++ (but not applicable to objc objects).

It comes close, but you just have to wait until the reference count reaches zero for -dealloc to be called, and that's why the guarantees are off (usually != always). This problem is actually quite similar to why you would never rely on or use -retainCount (where it is available). Examples: Autorelease Pools, exceptions, changes to the runtime or ARC generated code, compiler optimizations, using implementations which have different code generation flags could result in the life of the objc object being prolonged beyond the scope.

Update

The whole page on ARC at clang's site is a good read on the subject -- including details, guarantees (and lack of guarantees), but in particular:

6.1. Precise lifetime semantics

In general, ARC maintains an invariant that a retainable object pointer held in a __strong object will be retained for the full formal lifetime of the object. Objects subject to this invariant have precise lifetime semantics.

By default, local variables of automatic storage duration do not have precise lifetime semantics. Such objects are simply strong references which hold values of retainable object pointer type, and these values are still fully subject to the optimizations on values under local control.

Rationale: applying these precise-lifetime semantics strictly would be prohibitive. Many useful optimizations that might theoretically decrease the lifetime of an object would be rendered impossible. Essentially, it promises too much.

A local variable of retainable object owner type and automatic storage duration may be annotated with the objc_precise_lifetime attribute to indicate that it should be considered to be an object with precise lifetime semantics.

Rationale: nonetheless, it is sometimes useful to be able to force an object to be released at a precise time, even if that object does not appear to be used. This is likely to be uncommon enough that the syntactic weight of explicitly requesting these semantics will not be burdensome, and may even make the code clearer.

Even if you do use the objc_precise_lifetime attribute, it will apply to reference count operations for that strong local variable -- not the lifetime of the object.

like image 91
justin Avatar answered Sep 28 '22 08:09

justin