Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Instruments Leaks & Object Alloc: Are autoreleased objects counted as leaks?

I have an iPhone app that's getting memory warnings and so I'm trying to find leaks, make more efficient use of memory, etc., with the help of Instruments. Amongst other things, I'm trying to take out any autoreleased objects and replace with manual alloc/init/release objects. However, some API calls don't appear to have an 'init' version (see code below). I admittedly have some basic misunderstandings:

  1. If I 'call into' the API's and get back essentially autoreleased objects, can these objects show up as leaks in Instruments? It seems that I see this behavior in Instruments.

  2. If yes to 2, should I just ignore if there's no 'non-autorelease' alternative and I'm using an API that I need? Also, if this code gets called a lot, should I completely rethink the algor?

Here's some utility code from my application that gets called a lot. Basically determines if two dates are meaningfully 'equal'. I've left in the commented out code so you can see the types of improvements I'm going after in my codebase - this DID reduce the memory leaks when subsequently ran in Instruments as I started to manually create the NSDate (and release) which helped. However, I still have the date component objects which I believe are leaking...but it's an API call (sorry for the code formatting but I can't seem to improve it on SO):

+ (BOOL)isDayEqualToDay:(NSDate*)date anotherDate:(NSDate*)anotherDate
{

    NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
    //NSCalendar *cal;  
    NSDateComponents *componentsFromDate, *componentsFromAnotherDate;   
    NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;    
    //cal = [NSCalendar currentCalendar];
    componentsFromDate = [cal components:unitFlags fromDate:date];
    componentsFromAnotherDate = [cal components:unitFlags fromDate:anotherDate];

    BOOL bDatesEqual = ([componentsFromDate year] == [componentsFromAnotherDate year] && 
                        [componentsFromDate month] == [componentsFromAnotherDate month] && 
                        [componentsFromDate day] == [componentsFromAnotherDate day]);

    [cal release];

    return bDatesEqual;

    /*
    return (
        [componentsFromDate year] == [componentsFromAnotherDate year] &&
        [componentsFromDate month] == [componentsFromAnotherDate month] && 
        [componentsFromDate day] == [componentsFromAnotherDate day]
    );*/
}

I think the componentsFromDate and componentsFromAnotherDate are showing up as leaks but there just objects essentially returned from an NSData API call (autoreleased). Not sure what else I could really do to make this more efficient and I'm questioning my understanding of how to best use Instruments. Suggestions?

like image 454
Rob Avatar asked Mar 23 '09 18:03

Rob


2 Answers

Autoreleased object should not show up as memory leaks. Sometime APIs have memory leaks inside them however. You should file a bug report with apple. The new classes like NSCalendar and NSDateComponenets are especially suspect.

As for retain vs autorelease, the general rule is that it doesn't matter unless you are in a tight loop. In that case, if the tight loop is going many thousands of times without the event leaving, it means you never "cleanup" the autorelease pool.

like image 131
amattn Avatar answered Sep 28 '22 00:09

amattn


When using stuff like GCD there is an autorelease pool, but you have no way of knowing when (if ever) the default autorelease pool is drained. If you are convinced atoreleased objects aren't releasing, make sure you understand the threading api you're using. If memory serves me right GCD calls (dispatch_async) sorts out autorelease pools for you, BUT the actual draining of the pool can take a long while. NSOperations on the other hand let you do you own autorelease pooling.

I've seen memory leak detection in Instruments relying on 10 second intervals result in false mem leak warnings due to a prolonged delay before an auto release pool was drained. So try wrapping the offending code in:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
... [your code] ...
[pool drain];

I'd recommend against attempting to replace all autoreleases with manual releases. Using autorelease results in a ballanced retain/release call count in one spot. Creating an object and then autoreleasing it right away prevents lots of memory bugs in my opinion. Quick, easy. You will forget to release stuff when doing using manual release calls. Especially error conditions are tricky when doing manual releases.

Doing a pool yourself gives you more control and during allocation intensive work it can sometimes be beneficial to create and drain your own pools. But as always, try and test, don't make any assumptions.

like image 30
Jeroen Leenarts Avatar answered Sep 27 '22 22:09

Jeroen Leenarts