Update 2: Apple responded to my bug report with "We believe this issue has been addressed in iOS 4.2 b1 (8C5091e). Please let us know whether or not you continue to experience this issue with the newly released software by updating this bug report." I guess this acknowledges that the issue is in their code, not mine. I'll update with results when I or someone I know can update to try this.
Update: My coworker has reproduced the issue on a different computer and iPad, so it's probably not just a quirk with my setup.
This is strange.
I recently noticed the Leaks instrument reporting memory leaks in my application and NEVER pointing to my code in the stack traces, just various built-in libraries. Fortunately (?) I was able to strip out nearly everything and end up with a stupidly simple project that triggers this behavior every time, at least on my machine. Just to be sure, I've started a new project and gone through these steps and encountered the same behavior.
I'm using Xcode 3.2.4 and Instruments 2.7, on an iPad (non-3G) with iOS 3.2.2.
- I start a new "Window-based Application", targeting iPad and checking the "Use Core Data for Storage" box, which generates a bunch of property accessors for handy Core Data stuff in the app delegate. (I can post these if needed, but I don't change them at all from what it generates.)
- I edit the model to add one Entity, called "User", with no other attributes or relationships.
- I add a
-(void)loadUser
method to the app delegate and call it in-(BOOL)application:didFinishLaunchingWithOptions:
Here's the only bit of customized code, as described above.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[window makeKeyAndVisible];
[self loadUser];
return YES;
}
- (void)loadUser {
NSManagedObjectContext *moc = self.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"User"
inManagedObjectContext:moc];
[fetchRequest setEntity:entityDescription];
NSError *error;
NSLog(@"counting users");
NSUInteger count = [moc countForFetchRequest:fetchRequest error:&error];
if (count == NSNotFound) {
NSLog(@"error: %@", error);
} else if (count == 0) {
NSLog(@"creating user");
// make a user
NSManagedObject *object = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
if (![moc save:&error]) {
NSLog(@"error: %@", error);
}
[object release];
}
NSLog(@"fetching user");
NSArray *results = [moc executeFetchRequest:fetchRequest error:&error];
if (results) {
NSLog(@"results: %@", results);
} else {
NSLog(@"error: %@", error);
}
[fetchRequest release];
}
The count and insert is there because the leaks don't occur if there's no data, and this is the easiest way I know of to "populate" it. The logs are there just for straight-up sanity check; they can be removed and the leaks still show up.
This code seems completely innocuous to me. When I run it on the device with Leaks, I let it automatically check for leaks after a few seconds and it comes up with this, every time:
This does not occur on the simulator, but always occurs on the device.
Clearly something bizarre is happening here. JavaScriptCore? Where does that come into things? Here's the stack trace for one of those:
16 libSystem.B.dylib thread_assign_default
15 libSystem.B.dylib _pthread_start
14 WebCore RunWebThread(void*)
13 JavaScriptCore JSC::initializeThreading()
12 libSystem.B.dylib pthread_once
11 JavaScriptCore JSC::initializeThreadingOnce()
10 JavaScriptCore WTF::initializeThreading()
9 JavaScriptCore WTF::initializeMainThread()
8 JavaScriptCore WTF::initializeMainThreadPlatform()
7 libobjc.A.dylib objc_msgSend_uncached
6 libobjc.A.dylib _class_lookupMethodAndLoadCache
5 libobjc.A.dylib lookUpMethod
4 libobjc.A.dylib prepareForMethodLookup
3 libobjc.A.dylib _class_initialize
2 libobjc.A.dylib _fetchInitializingClassList
1 libobjc.A.dylib _objc_fetch_pthread_data
0 libobjc.A.dylib _calloc_internal
None of the stack traces mentions my code. I'm doing no explicit multithreading. There are no web views or anything else to do with JavaScript involved. On my machine, I consistently get this result just by following the steps above. I've deleted and reinstalled the app on the iPad. I've restarted Xcode, restarted the iPad, and restarted my computer. Same deal.
My questions:
Can other people reproduce the same issue? (edit: one person has, on a different computer and iPad)
If not, I guess it's some strange problem with my configuration, and I'd like to know what I can do to fix it.
If so, what the hell is happening? Is my code at fault? Is this not how I should be fetching objects? Is it a false positive from Leaks, or a bug in Core Data? Is there a workaround? I'd really like to be able to accurately detect leaks, and this is making it hard to do so.