1

I am not clear about how to use autorelease;

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
RetainTracker* tracker = [RetainTracker new];
[tracker retain];
[tracker retain];
[tracker autorelease];
[pool release];

Is there any memory leak in the above code?

I know the autorelease just puts tracker into NSAutoreleasePool, without modifying the reference count for tracker. When i call [pool release], the object receives one message release, then the reference count of tracker is 2. So the compiler can't call the dealloc function of object tracker, so there is a memory leak.

So i get this: we shoul call retain and release same times, is it right?

BlackMamba
  • 10,054
  • 7
  • 44
  • 67
  • Not sure what `RetainTracker` is, but you retain twice then only autorelease once, so yes, it will leak (unless `RetainTracker` has funny behaviour). `autorelease` is just like calling `release` as far as final retain count goes, it just waits until the pool is released before applying. You can use it to keep temporaries alive for long enough in statements. – Dave Sep 08 '13 at 13:09
  • +1 for asking a good question and having me re-read memory management docs again for the first time in a long time. – Michael Dautermann Sep 08 '13 at 13:24
  • 3
    It's actually retained 3 times, the `new` and the two `retain`s – Jonathan. Sep 08 '13 at 13:26
  • Just as an aside, I favour the Objective-C 2.0 `@autorelease { … }`, as the scope is clearer. – Michael Sep 08 '13 at 13:16

2 Answers2

4

If you're new to Objective-c, you should be using Automatic Reference Counting. Almost everyone should. But for the sake of understanding:

An object has a reference count of how many objects have a reference to it. When it drops to zero, the object is not referenced by anything and is deallocated. Every method in Objective-C is responsible for releasing any object it retains. The problem is, if a factory method's job is to create an object, it's breaking the rules by not releasing an object it retained (in this example it was retained because it was created). If the method called release on the object right before returning it, it would be returning the address to an object that is already gone. So, there is autorelease, which temporarily delays the release until the calling method can retain the object the called method created.

In your example above, if you got rid of the 2 retains, and only called autorelease, then the object would get released and deallocated when the autorelease pool is released and (right before deallocation) is drained, meaning it calls release on all objects in its pool, tracker being one of them because calling autorelease on tracker added it to the pool.

John Topley
  • 113,588
  • 46
  • 195
  • 237
atomkirk
  • 3,701
  • 27
  • 30
1

new is equivalent to doing an "alloc" & "init", so retain count on tracker on that line is 1.

Then you increment the retain count 2 more times to give a total retain count of 3.

Autorelease sets the tracker to be released when the pool is released (and the retain count is decremented as well). But it's already retained 3 times, so it doesn't really get released.

And yeah, there is a memory leak with the retain count being greater than 0 and no reference to "tracker" outside of that method (that is, unless you're using "tracker" in an instance variable).

It's very good to know the basics of memory management; but if you want to save yourself a ton of headache, just do what everyone else here seems to be saying and simply enable ARC.

EDIT: And to finish your question, you should make sure every call to retain is balanced with a release. You also do a "new", which also increments the retain count so you need to "release" because of that as well.

Community
  • 1
  • 1
Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215