iOS内存泄漏根据仪器

时间:2011-09-20 21:05:56

标签: ios memory-management instruments

Screen shot of memory leak in instruments

请帮忙!我已经阅读了内存管理规则,但也许我错过了某些地方。仪器告诉我,我在以下代码上有泄漏:

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%

Keys和Objects数组没有被分配或初始化,所以我不认为我需要释放它们?

然后对象内的数字正在自动释放,所以他们没关系不是吗? 并且sPlateToAdd是一个传递给此代码所在方法的字符串,所以我不是它的所有者,所以我不需要释放它。还是我?

我必须在某处做错事。

该应用程序在iPad上运行完全正常,但在iPhone 3GS上速度较慢,我希望修复此内存泄漏可能会加快一点......

这是创建self.aFinals的方法,它从文本输入传递一个字符串。我已经省略了一些行但是self.aFinals不与它们交互

-(id)initWithTerm:(NSString *)thisTerm {
    ...
    ...
    self.aFinals = [[NSMutableArray alloc] init];

    return self;
}

然后我有大约5个嵌套循环,在所有循环的中间调用addPlateToFinals 3次,创建 thisPlate ,变为 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

这是泄漏源自的完整方法:

-(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];   
        }
    }
}

}

3 个答案:

答案 0 :(得分:3)

你应该显示整个`addPlateToFinals'方法,sPlateToAdd可能会泄漏。

如果使用retain声明属性,则基于新添加的代码self.aFinals正在泄漏(并且我是%99)。应该是:

self.aFinals = [[[NSMutableArray alloc] init] autorelease]

甚至更好:

self.aFinals = [NSMutableArray array]

答案 1 :(得分:0)

如果可能的话,你应该使用NSDictonary而不是NSMutableDictonary,因为对象的可变版本比不可变的占用更多的内存。另外,我对代码做了一些美容增强

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%

答案 2 :(得分:0)

此对象的内存泄漏可能没有此代码负责。

Cocoa / Cocoa Touch环境中的内存泄漏发生在一个对象保留超过它的释放时。这些工具将指出它的分配位置,而不是泄漏的位置,因为工具无法确定哪个保留缺少一个版本。他们只是保留和释放;没有什么可以将它们联系在一起但只是约定。

首先,做一个Build&amp;分析。这可能会指出您的代码在哪里做了不正确的导致泄漏的事情。严肃对待分析器警告,特别是如果它们与内存管理有关。

如果Build&amp;分析不能解决您的问题,再次通过您的应用程序进行分析并研究泄漏块的历史记录。这将在每次保留或释放块时显示。寻找没有相应释放或自动释放的保留。 (实际上,您可能会更容易阅读代码,寻找不平衡的保留,而无需使用仪器。)