简体   繁体   中英

iOS memory leak according to instruments

仪器内存泄漏的屏幕快照

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM