My question is about basic data and memory usage. I used to use basic data, but this time the amount of data is higher, and this made me realize that there was much more to know. I saw that there are several other similar messages, and I have interesting information from them, but after applying it, my applications still fail. I have been dealing with this issue for a week now. Someone please help.
In principle, I have three subsequent similar cycles of 64, 15 and 17 iterations, respectively. They work great on a simulator. Tested on a pair of iPads, they receive memory alerts, and they crash at the same iteration (number 34 of the first loop). After testing the iPad 2, it will work at number 14 of the second cycle. The tools show memory usage of about 1.5 MB both in real time and in general. There are leaks for a few kilobytes.
Loops do the following (code below)
- Fetch with kernel data
- For each record, take a parameter stored as an attribute of a string property (String)
- Call a procedure that takes this parameter and which returns data (about a hundred KB)
- Save this data in another property attribute (Transformable) of the same row
Pretty common task isn't it?
Now that I have problems with memory, I tried to use all the tools I know that:
- release owned asap objects
- create autodetection pools and merge them as soon as possible for objects that do not belong to them
- keep context as soon as possible
- turn objects into errors as soon as possible
After applying all these methods, I got an exciting result: the application crashes at the same point as before.
Here is the code.
- (void) myMainProcedure { [self performLoop1]; [self performLoop2]; // Similar to loop1 [self performLoop3]; // Similar to loop1 } - (void) performLoop1 { NSError * error = nil; NSAutoreleasePool * myOuterPool; NSAutoreleasePool * myInnerPool; NSManagedObjectContext * applicationContext = [[[UIApplication sharedApplication] delegate] managedObjectContext]; [applicationContext setUndoManager:nil]; NSEntityDescription * myEntityDescription = [NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:applicationContext]; NSFetchRequest * myFetchRequest = [[NSFetchRequest alloc] init]; [myFetchRequest setEntity:myEntityDescription]; NSString * column = @"columnName"; NSPredicate * aWhereClause = [NSPredicate predicateWithFormat: @"(%K = %@)", column, [NSNumber numberWithInt:0]]; [myFetchRequest setPredicate: aWhereClause]; myOuterPool = [[NSAutoreleasePool alloc] init]; NSArray * myRowsArray = [applicationContext executeFetchRequest:myFetchRequest error:&error]; NSMutableArray * myRowsMutableArray = [[NSMutableArray alloc] initWithCapacity:0]; [myRowsMutableArray addObjectsFromArray: myRowsArray]; [myOuterPool drain]; [myFetchRequest release]; EntityName * myEntityRow; int totalNumberOfRows = [myRowsMutableArray count]; myOuterPool = [[NSAutoreleasePool alloc] init]; for (int i = 0; i < totalNumberOfRows; i++) { myInnerPool = [[NSAutoreleasePool alloc] init]; myEntityRow = [myRowsMutableArray objectAtIndex:0]; NSString * storedSmallAttribute = myEntityRow.smallAttribute; UIImageView * largeData = [self myMethodUsingParameter: smallAttribute]; myEntityRow.largeAttribute = largeData; [myRowsMutableArray removeObjectAtIndex:0]; [applicationContext save:&error]; [applicationContext refreshObject:myEntityRow mergeChanges:NO]; [myInnerPool drain]; [largeData release]; } [myOuterPool drain]; [myRowsMutableArray release]; } - (UIImageView *) myMethodUsingParameter : (NSString *) link { UIImageView * toBeReturned = nil; NSURL *pdfURL = [NSURL fileURLWithPath:link]; CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL); CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1); CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); UIGraphicsBeginImageContext(pageRect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0); CGContextFillRect(context,pageRect); CGContextSaveGState(context); CGContextTranslateCTM(context, 0.0, pageRect.size.height); CGContextScaleCTM(context, 1, - 1); CGContextSetInterpolationQuality(context, kCGInterpolationHigh); CGContextSetRenderingIntent(context, kCGRenderingIntentDefault); CGContextDrawPDFPage(context, page); CGContextRestoreGState(context); UIImage *imageToBeReturned = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CFRelease(pdf); toBeReturned = [[UIImageView alloc] initWithImage:imageToBeReturned]; UIGraphicsEndImageContext(); return toBeReturned; }
note that
- A volatile array was introduced as a (apparently useless) strategy for eating objects released earlier
- An ad part of the same strategy has been added to pools.
- The statement about the quality of interpolation was the only one who could improve the situation (say, to move the accident) a little forward).
- Keeping the counter for managed objects within a cycle of 6 to 10 (?) I know that rc is not valuable but still, I did a test and I found out that I can send messages with several versions of objects before forcing the application to crash for of this. But the fact is that I should not release an object that I do not have, right? ....
- The entity on which the request is set also has some bi-directional relationships with other entities, but is it still meaningful?
Thanks.