e-Jah
e-Jah

Reputation: 335

Memory leaks on autorelease objects?

I am running Instruments to find the memoryleaks in my iPhone app.

As you can see on the screenshot below, I get some weird memory leaks, from some Foundation objects.

Screenshot form Instruments

The ones that bother me the most are the one that should be released "automatically" if I understood right. Such as: NSPredicate predicateWithFormat, NSKeyedUnarchiver unarchiveObjectWithData, and so...

Here a screenshot with more info for the NSPredicate one: enter image description here

Can you please help me to understand what ma I doing wrong?

In the code I am simply doing that:

NSPredicate *basePredicate = [NSPredicate predicateWithFormat:@"ANY fcLists IN %@", listsIds];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:self.context];
[self.fetchRequest setEntity:entity];

// Load the list of new items
NSPredicate *addedPredicate = [NSPredicate predicateWithFormat:@"fcStatus = -2"];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:basePredicate, addedPredicate, nil]];
[self.fetchRequest setFetchLimit:self.nbOfNewItems];
[self.fetchRequest setPredicate:predicate];
tmp = [self.context executeFetchRequest:self.fetchRequest error:&error];

so I shouldn't have to release predicate right? Anyway I tried and it makes my code to crash...

Thank you in advance for your help!

Upvotes: 0

Views: 1229

Answers (1)

Steven Fisher
Steven Fisher

Reputation: 44886

The retain/release model is not like (for instance) malloc/free. It isn't enough to balance your object creation with a release, or to use a method that returns an autoreleased objects. Every retain on an object must be balanced with a release. If you miss just one, the object is leaked. Instruments points out where the object was created, but not where it was leaked. Instruments points out each retain, but does not (and can not) point out which retain is not properly balanced.

You didn't specify what was actually leaking, so I'll have to give a generic example based on your code.

Let's assume basePredicate was leaking:

  1. This simplest case for basePredicate leaking is that you simply haven't called release on it. In this case, though, you're creating it with a method that returns an autoreleased object.
  2. The next possibility is that you're giving some other object a share of ownership in basePredicate (i.e. it calls retain). That object isn't releasing it.
  3. The next possibility is that you're giving some other object a share of ownership in basePredicate, as above, but that object does release it. It's possible that object hands basePredicate off to some other object that claims ownership of it by retaining it.
  4. Next, it's possible that the object that you've given ownership of is itself being leaked.
  5. There are very nearly an infinite number of permutations of the last three scenarios.

If this sounds horrible, it kind of is. But the fix is actually simple: Make sure every time your code claims ownership of an object with retain (or assignment to a property with retain), it has a corresponding yield of ownership, in the form of a release or autorelease (or assignment of nil to the property).

In the past, when I've had a leak I just can't find, I've found the best thing to do is study which objects leak and identify what (if any) relationship they have. Then I go through my code and look for objects I haven't released.

Also, if you haven't yet, start using the static analyzer. It can't find all problems like this, but when it does find one you'll save a lot of time.

Upvotes: 1

Related Questions