想知道我是不是有内存泄漏(报告为潜在)

Posted

技术标签:

【中文标题】想知道我是不是有内存泄漏(报告为潜在)【英文标题】:Wondering do i have a mem leak(reported as potential)想知道我是否有内存泄漏(报告为潜在) 【发布时间】:2011-01-31 20:21:07 【问题描述】:

我在我的 do-while 循环之外创建了一个名为 mutableScoreHolder 的 NSMutableString。 我分配它,将其“复制”到另一个名为“Match”的对象中,该对象包含一个 NSString。

当我构建和分析代码时,它会报告我的 mutableScoreHolder 的潜在内存泄漏。

NSString * scoreHolder;
NSMutableString * mutableScoreHolder;
count = 1;
numMatchCounter = 0;
int startOfScoreIndex = 0; 
int endOfScoreIndex = 0;
int numberOfGoals=0;
do  

    match = [substring rangeOfString: @"points_bg"];

    if (match.location == NSNotFound) 
    
        break;
    
    if  ((match.location + match.length) > ([substring length]))
    
        break;
    

    substring = [substring substringFromIndex:(match.location + match.length)];

    match2 = [substring rangeOfString: @">"];   
    startOfScoreIndex = match2.location+1;

    match2 = [substring rangeOfString: @"<"];
    endOfScoreIndex = match2.location;

    if ((count % 2) == 1)
    
        scoreHolder = [substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))];
        mutableScoreHolder = [[NSMutableString alloc] initWithString:scoreHolder];
        numberOfGoals += [scoreHolder intValue];
    
    else 
    
        Match *aMatch = [theMatchScoresArray objectAtIndex:(numMatchCounter)];
        numberOfGoals += [[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))] intValue];
        [scoreHolder stringByAppendingString:@" - "];
        [mutableScoreHolder appendString:@" - "];
        [scoreHolder stringByAppendingString:[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))]];
        [mutableScoreHolder appendString:[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))]];

        aMatch.theScore = [mutableScoreHolder copy];
        aMatch.matchGoalCount = numberOfGoals;
        numMatchCounter++;
        numberOfGoals=0;

       
    count++;

while ( match.length != 0 );

这是我的匹配对象类。

@interface Match : NSObject 

NSString *teamName1;
NSString *teamName2;
NSString *theScore;
int matchGoalCount;
NSMutableArray *scorersArray;
NSMutableArray *scorerOrderArray;
NSString *matchStatus;
NSString *matchDate;
bool matchNotStarted;
   
@property(nonatomic) int matchGoalCount;
@property(nonatomic) bool matchNotStarted;
@property(nonatomic, retain) NSString *teamName1;
@property(nonatomic, retain) NSString *teamName2;
@property(nonatomic, retain) NSString *theScore;
@property(nonatomic, retain) NSString *matchStatus;
@property(nonatomic, retain) NSString *matchDate;
@property(nonatomic, retain) NSMutableArray *scorersArray;
@property(nonatomic, retain) NSMutableArray *scorerOrderArray;

-(id)init;
@end

#import "Match.h"


@implementation Match
@synthesize teamName1;
@synthesize teamName2;
@synthesize theScore;
@synthesize scorersArray;
@synthesize matchDate;
@synthesize matchStatus;
@synthesize matchGoalCount;
@synthesize scorerOrderArray;
@synthesize matchNotStarted;


-(id)init

//NSLog(@"****** MATCH INIT ******");
self = [super init];
scorersArray =[[NSMutableArray alloc] init];
scorerOrderArray =[[NSMutableArray alloc] init];
return self;    


-(void) dealloc

[scorersArray release];
[scorerOrderArray release];
[teamName1 release];
[teamName2 release];
[theScore release];
[matchStatus release];
[matchDate release];
[scorersArray release];
[scorerOrderArray release];
[super dealloc];    

@end

当我运行仪器检查泄漏时,我确实发现有一个字符串泄漏。所以我认为这个“潜在的泄漏”可能就是我看到的泄漏。

因为分数有保留

@property(nonatomic, retain) NSString *theScore;

还有一个字符串复制到里面

aMatch.theScore = [mutableScoreHolder copy];

可以将保留计数设为 2 吗?那么泄漏呢?

抱歉这个复杂的问题!我的头在旋转,试图绕过它。

谢谢 -代码

【问题讨论】:

【参考方案1】:

你肯定在这里泄漏,有两个不同的原因。

首先是你分配/初始化一个 NSMutableString 并将其填充到 mutableScoreHolder 中。这是一个局部变量,一旦这个值超出范围(或在下次创建新数组时被替换),旧值就会泄露。这应该是一个自动释放的值,如[NSMutableString stringWithString:scoreHolder]

第二个是复制字符串并将结果值填充到属性中。您应该做的是将该属性重新声明为副本

@property(nonatomic, copy) NSString *theScore;

然后直接将mutableScoreHolder 分配给该属性

aMatch.theScore = mutableScoreHolder

使用现有代码复制数组,然后属性会保留它。通过此更改,属性直接复制它,并且不使用额外的保留。

注意,一般来说,将支持类型的属性声明为copy 是个好主意。这包括 NSString、NSArray、NSDictionary 等。如果您将一个已经不可变的对象分配给该属性,则 copy 会回退到 retain 并且不会影响性能。但是在像您这样分配可变对象的情况下,它会根据需要复制它并在属性中保留不可变快照。

【讨论】:

嗨,Kevin,所以将匹配中的所有 NSString 和 NSMutableArray 从“保留”更改为“复制”是安全的,这样会更安全吗?我已经更改了 theScore 并且运行良好。谢谢 如果您有一个属性,其中类型是具有可变变体的不可变类(例如 NSString、NSArray、NSDictionary 等),使用copy 往往是个好主意。这需要类型支持 NSCopying,但所有看起来像这样的 Cocoa 类都支持复制。【参考方案2】:

还有一个字符串复制到里面

aMatch.theScore = [mutableScoreHolder copy]; 

这样可以吗 保留计数为 2?然后 泄漏?

没错。您可以将theScore 的属性从retain 更改为copy 来解决此问题。那么你可以使用aMatch.theScore = mutableScoreHolder;

并且(至少)还有另一个泄漏:

mutableScoreHolder = [[NSMutableString alloc] initWithString:scoreHolder];

这永远不会被释放。

【讨论】:

以上是关于想知道我是不是有内存泄漏(报告为潜在)的主要内容,如果未能解决你的问题,请参考以下文章

了解 LeakCanary 内存泄漏堆栈跟踪

解释 objgraph 数字:内存泄漏?

潜在的内存泄漏 abaddressbookcopyarrayofallpeople( )

iOS - XCode 4.4 - 使用分析的潜在内存泄漏

Tomcat 停止线程以避免潜在的内存泄漏

为啥 Instruments 将此报告为内存泄漏?