Please help! I've read the memory management rules, but maybe I'm missing them point somewhere. Instruments is telling me I've got leaks on the following code:
NSArray *keys = [NSArray arrayWithObjects:@"text", @"score", @"subCount", nil];
NSArray *objects
= [NSArray arrayWithObjects:sPlateToAdd, [
[[NSNumber alloc] initWithInt:1] autorelease],
[[[NSNumber alloc] initWithInt:1] autorelease],
nil];
NSMutableDictionary *dPlateToAdd
= [NSMutableDictionary dictionaryWithObjects:objects forKeys:keys]; // 93.4%
[self.aFinals addObject:dPlateToAdd]; // 6.6%
the Keys and Objects arrays aren't being alloc'ed or init'ed, so I dont think I need to release those?
Then the numbers inside Objects are being auto released, so they're ok aren't they? And sPlateToAdd is a string that gets passed into the method this code is in, so I'm not the owner of that, so I don't need to release it. Or am I?
I've got to be doing something wrong somewhere.
The app runs completely fine in the iPad, but is dog slow on an iPhone 3GS, I'm hoping fixing this memory leak might speed it up a little...
This is the method that creates self.aFinals, which is passed a string from a text input. I've ommitted some of the lines but self.aFinals doesn't interact with them
-(id)initWithTerm:(NSString *)thisTerm {
...
...
self.aFinals = [[NSMutableArray alloc] init];
return self;
}
Then I have about 5 nested loops, that call addPlateToFinals 3 times in the middle of all the loops, creating thisPlate , which becomes sPlateToAdd
// replace 1st occurance
NSString *thisPlate = [thisBase
stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:
@"(^[^%@]+)%@(.*$)",
thisChar,
thisChar]
withString:[NSString stringWithFormat:@"$1%@$2", thisSub]
];
[self addPlateToFinals:thisPlate withSubCount:thisSubCount];
// replace 2nd occurance
thisPlate = [thisBase
stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:
@"(^[^%@]+%@.*)%@",
thisChar,
thisChar,
thisChar]
withString:[NSString stringWithFormat:@"$1", thisSub]
];
// then it does it again, with slightly different regex
This is the complete method that the leak is coming from:
-(void)addPlateToFinals:(NSString *)sPlateToAdd withSubCount:(NSNumber *)nSubCount {
// plate must be less than 7 characters and great than 2 chars
if (
[sPlateToAdd length] <= [self.nPlateMax intValue] &&
[sPlateToAdd length] >= [self.nPlateMin intValue]
) {
NSMutableArray *aSearchFinals = [self arrayOfFinals];
// add plate if it is not already in the finals array
if(![aSearchFinals containsObject:sPlateToAdd]) {
// filter out results that cannot be converted to valid plates
NSPredicate *potential = [NSPredicate predicateWithFormat: @"SELF MATCHES '^[a-z]{0,3}[0-9]{1,3}[a-z]{0,3}$'"];
NSPredicate *impossible1 = [NSPredicate predicateWithFormat: @"SELF MATCHES '^[a-z]{2}[0-9]{2,3}[a-z]{2}$'"];
NSPredicate *impossible2 = [NSPredicate predicateWithFormat: @"SELF MATCHES '^[a-z][0-9]{3}$'"];
NSPredicate *impossible3 = [NSPredicate predicateWithFormat: @"SELF MATCHES '^[a-z]{2}[0-9]{2}$'"];
NSPredicate *impossible4 = [NSPredicate predicateWithFormat: @"SELF MATCHES '^[0-9]{2}[a-z]{2}$'"];
if(
[potential evaluateWithObject: sPlateToAdd] &&
![impossible1 evaluateWithObject: sPlateToAdd] &&
![impossible2 evaluateWithObject: sPlateToAdd] &&
![impossible3 evaluateWithObject: sPlateToAdd] &&
![impossible4 evaluateWithObject: sPlateToAdd]
){
NSArray *keys = [NSArray arrayWithObjects:@"text", @"score", @"subCount", nil];
NSArray *objects = [NSArray arrayWithObjects:
sPlateToAdd,
[[[NSNumber alloc] initWithInt:1] autorelease],
[[[NSNumber alloc] initWithInt:1] autorelease],
nil
];
NSDictionary *dPlateToAdd = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
[self.aFinals addObject:dPlateToAdd];
}
}
}
}
You should show the entire `addPlateToFinals' method, sPlateToAdd could be leaking.
Based on the new added code self.aFinals
is leaking if the property is declared with retain(and I'm %99 it is). Should be:
self.aFinals = [[[NSMutableArray alloc] init] autorelease]
or even better:
self.aFinals = [NSMutableArray array]
You should use NSDictonary instead of NSMutableDictonary if it is possible, because mutable versions of the objects take more memory than immutable . Also, I have done some cosmetic enhancements to the code
NSArray *keys = [NSArray arrayWithObjects:@"text", @"score", @"subCount", nil];
NSArray *objects = [NSArray arrayWithObjects:sPlateToAdd,
[NSNumber numberWithInt:1],
[NSNumber numberWithInt:1],
nil];
NSDictonary *dPlateToAdd = [NSDictonary dictionaryWithObjects:objects forKeys:keys]; // 93.4%
[self.aFinals addObject:dPlateToAdd]; // 6.6%
You may have a memory leak of this object without this code being responsible at all.
A memory leak in the Cocoa/Cocoa Touch environment happens when an object is retained more than it's released. The tools will point out where it was allocated, not where it was leaked, because the tools have no way to determine which retain is missing a release. They're just retains and releases; nothing really ties them together but conventions.
First, do a Build & Analyze. This might point out where your code is doing something improper causing a leak. Treat Analyzer warnings seriously, especially if they're related to memory management.
If Build & Analyze doesn't fix your problem, profile through your app again and study the history of the leaked block. This will show you each time the block was retained or released. Look for retains without a corresponding release or autorelease. (You may actually find it easier to simply read through your code, looking for unbalanced retains, without Instruments.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.