NSDateFormatter memory leak

This is a follow-up to a post on stackoverflow.com, where it appears that 1 MB is lost after invoking NSFormatter -dateFromString.

I ran into the same situation, with very similar leak sizes to the ones reported on that article. Instruments shows that 868 Kb (889520 bytes to be exact) are allocated by Cocoa on iPhone OS (verified from 2.x to 3.x up to 3.1.3).

1. Z Offending Code

The objective of this method is to convert a string into a date.
Note that I do invoke -release on the NSDateFormatter object, and that the newly created NSDate is destroyed when the NSAutoreleasePool is drained. This is not where the problem lies.

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[ NSTimeZone timeZoneWithName:@"GMT"]];
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss z"];
[dateFormatter setLenient:YES];
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSDate *testDate = [dateFormatter dateFromString:string]; // <- Allocates 868 Kb
// Do something with testDate
[pool drain];
}
[dateFormatter release];

2. Discussion

It appears that this is caused by the z option in setDateFormat.
My guess is that Cocoa allocates exactly 8618 time-zone related objects that live in memory for the duration of the application.
I do not know of any workaround, other than not using the “z” option.
[ dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss"];

3. Instruments log

Here is the allocation log for the first 3 of the 8618 objects, allocated all at once by a single invocation to dateFromString. Without going into too much details, suffice it to say that I used “Created & Still Living” option in “Allocation Lifespan”, and that the “Extended Detail” view in Instruments shows that all those objects are created back to back as the result of the CoreFoundation CFDateFormatterGetAbsoluteTimeFromString method.

# Address Category Time Size Library Caller
2280 0xa20be00 GeneralBlock-32 01:07.742 32 Foundation -[NSDateFormatter getObjectValue:forString:range:error:]
2281 0xa219670 GeneralBlock-176 01:07.833 176 Foundation -[NSDateFormatter getObjectValue:forString:range:error:]
2282 0xa298db0 GeneralBlock-48 01:07.833 48 Foundation -[NSDateFormatter getObjectValue:forString:range:error:]

4. All 8618 Objects

The entire log (8618 entries) can be viewed here.

5. Conclusion

The StackOverflow.com positively isolates the problem and the workaround. Do not use setDateFormat:@”EEE, d MMM yyyy HH:mm:ss z“, unless you are willing to loose 868 Kb for the rest of the lifetime of the application. The alternative is to not use the time zone which is, I agree, a pain: setDateFormat:@”EEE, d MMM yyyy HH:mm:ss”.

A possible approach is to test the string against ” GMT”, and to only invoke “z” when not in GMT:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
if( ![string hasSuffix:@" GMT"]) {
// If the string is not GMT, we must use time zone :-(
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss z"];
} else {
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss"];
}

As of today’s date iPhone GB cost, your user either $0.005 or $0.01, depending on which device she or he bought.

6. External Links

 

DeliciousBookmark this on Delicious

 

2 Responses to “NSDateFormatter memory leak”

  1. DEV» Blog Archive » Finding hidden memory leak with Instruments said:

    Mar 23, 10 at 7:20 am

    […] the 1 Mb NSDateFormatter memory leak as a case-study, this tutorial shows how to locate and isolate unexpected memory allocation using […]

  2. Tweets that mention DEV» Blog Archive » NSDateFormatter memory leak -- Topsy.com said:

    May 18, 10 at 4:13 pm

    […] This post was mentioned on Twitter by Sam Lu. Sam Lu said: Ran my partial iPhone app through XCode's instruments. Found a puzzling leak which seems to be a flaw in Cocoa… http://bit.ly/a13NdY […]


Leave a Reply

Due to a sudden burst of interest from unidentified aliens, you must now to post a comment.