I can't figure out why my iPhone App is running out of memory
I am loading a bunch of data from a text file into CoreData. For some reason, every iteration through the for (line in lines) loop in the code below is allocating new memory. It works fine up until it can't allocate new memory. I can't see why it's not reusing the same memory for each iteration. What am I doing wrong? Any help would be appreciated.
`
-(IBAction)loadDataInThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"MileMarkers" ofType:@"csv"];
NSData *myString = [NSString stringWithContentsOfFile:filePath];
NSArray *lines = [myString componentsSeparatedByString:@"\r"];
status.hidden = FALSE;
// NSManagedObjectContext *context = [self managedObjectContext];
NSFileManager *fileman = [NSFileManager defaultManager];
NSString *tileDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Tiles"];
NSString *line;
NSNumberFormatter * myNumFormatter = [[NSNumberFormatter alloc] init];
[myNumFormatter setLocale:[NSLocale currentLocale]];
[myNumFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[myNumFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSManagedObject *newManagedObject;
NSArray *fields;
// NSLog(@"Loading Markers");
for (line in lines) {
fields = [line componentsSeparatedByString:@","];
self.stat = [NSString stringWithFormat:@"%@ %@ %@ %@",[fields objectAtIndex:0],[fields objectAtIndex:1],[fields objectAtIndex:2],[fields objectAtIndex:3]];
NSLog(stat);
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"MileMarkers" inManagedObjectContext:self.managedObjectContext];
NSNumber *f1 = [myNumFormatter numberFromString:[fields objectAtIndex:0]];
NSNumber *f2 = [myNumFormatter numberFromString:[fields objectAtIndex:1]];
NSNumber *f3 = [myNumFormatter numberFromString:[fields objectAtIndex:2]];
NSNumber *f4 = [myNumFormatter numberFromString:[fields objectAtIndex:3]];
[newManagedObject setValue:f1 forKey:@"ICWID"];
[newManagedObject setValue:f2 forKey:@"MileMarker"];
[newManagedObject setValue:f3 forKey:@"Latitude"];
[newManagedObject setValue:f4 forKey:@"Longitude"];
NSMutableArray *charts = [[NSMutableArray alloc] initWithCapacity:4];
NSDirectoryEnumerator *e开发者_如何学JAVA = [fileman enumeratorAtPath:tileDirectory];
NSString *path;
int idx = 0;
/*
for (path in e) {
NSString *pathFileName = [NSString stringWithFormat:@"%@/%@/tilemapresource.xml",tileDirectory,[path stringByDeletingPathExtension]];
// NSLog(@"parsing %@",pathFileName);
BOOL checkFile = [self checkForLatLong:pathFileName latitude:f3 longitude:f4 ];
if (checkFile) {
NSLog(@"Match %d",idx);
if (idx < 4){
self.counter.text = [NSString stringWithFormat:@"%d",idx];
[charts insertObject:path atIndex:idx];
idx++;
}
}
}
[path release];
for (int lp=1; lp<[charts count]; lp++) {
NSString *keyName = [NSString stringWithFormat:@"Chart%d",lp+1];
[newManagedObject setValue:[charts objectAtIndex:lp] forKey:keyName];
}
[charts release];
*/
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[error release];
}
[myNumFormatter release];
NSLog(@"Markers Loaded");
[self performSelectorOnMainThread:@selector(dataLoaded) withObject:nil waitUntilDone:YES];
[pool release];
} `
It's likely that you're producing lots of autoreleased objects inside this loop. Remember that autoreleased objects are still valid until the end of the whole event loop, at which point the autorelease pool is drained. Normally this process works more or less invisibly, but if you have loops that allocate lots of autoreleased objects, you can run out of heap.
You can alleviate this by creating and draining an inner autorelease pool within your loop, like so:
for (line in lines) {
NSAutoreleasePool * localPool = [[NSAutoreleasePool alloc] init];
...
[localPool release];
}
You should also explicitly release any created/retained objects that you don't need any more, like "charts" etc in the above.
The "charts" mutable array is not being released.
This line,
NSMutableArray *charts = [[NSMutableArray alloc] initWithCapacity:4];
You have to release charts after you're done with it, like this:
[a1 release]
Classic memory management problem.
Check this out... memory management
There are tons of other links out there as well...
In Objective-C, always remember this tag line-
When you use alloc or new or make a copy, you should definitely release it.
That is you are managing the resources not the compiler. So it is your job to release them.
More Information
精彩评论