2013-01-22 36 views
0

我有一个每秒触发一次的NSTimer。MutableCopy AllocLeak MemoryLeak

每隔一秒我有一个NSString需要改变。

我从来没有试过处理内存管理,所以我不确定我所做的是正确的,但仪器在“alloc”下面说stringByReplacingOccurrencesOfString的代码行有45MB的“Live Bytes “大约一分钟后......

(并且活动字节计数每秒都在持续上升并最终导致应用程序崩溃)。

我认为我的问题在于某处与MutableCopy代码?

这里是我的代码:

-(void)myTimer { 
    if (testedit) { 
     [testedit release]; 
     [withString1a release]; 
     [forString1a release]; 
    } 
    testedit = [[NSString alloc] init]; 
    withString1a = [[NSString alloc] init]; 
    forString1a = [[NSString alloc] init]; 

    testedit = [[NSString alloc] initWithFormat:@"example"]; 
    withString1a = [[NSString alloc] initWithFormat:@"e"];//this string gets its values randomly from an array in my real code 
    forString1a = [[NSString alloc] initWithFormat:@"flk34j"];//this string gets its values randomly from an array in my real code 

    testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];//memory leak /: 

} 
+1

你为什么要做这么多的分配?你在使用ARC吗? – iDev

+0

不,ARC被禁用。 /: –

+0

您是否将'testedit'声明为'@ property'还是仅仅是一个类的变量? – iDev

回答

2

您分配内存为每个对象的两倍。当您第二次分配并将其分配给同一个变量时,第一块alloc的内存变得不可访问且不可释放。

然后你制作一个可变拷贝的被测试者,并把拷贝分配给原来的变量。同样,你留下了一块无法访问的内存。

与非ARC内存管理的规则是 - 每一个ALLOC复制保留,你需要有一个相应的释放。你有6个分配,一个副本,只有3个版本。

这里有一些建议。

删除这些复制的分配:

testedit = [[NSString alloc] init]; 
    withString1a = [[NSString alloc] init]; 
    forString1a = [[NSString alloc] init]; 

想必testeditwithString1aforString1a都是高德。 (Please declare your iVars as autosynthesized properties并将它们称为self.testedit ...等,这将使您的代码更清晰地堆栈溢出)。

取出了这一切:

if (testedit) { 
     [testedit release]; 
     [withString1a release]; 
     [forString1a release]; 
    } 

假设这些都是实例变量,释放他们的正确的地方是在你的对象的dealloc方法

事实上withString1aforString1a可以是局部变量,你从别处得到他们的内容:

NSString* withString1a = [[[NSString alloc] initWithFormat:@"e"] autorelease]; 
NSString* forString1a = [[[NSString alloc] initWithFormat:@"flk34j"] autorelease]; 

你可以autorelease他们为你在方法结束后不需要它们挂起。

这些线也可写成:

NSString* withString1a = [NSString stringWithFormat:@"e"]; 
NSString* forString1a = [NSString stringWithFormat:@"flk34j"]; 

(-stringWithFormat是返回自动释放物体一个方便的方法)

这给我们留下了这两条线。

testedit = [[NSString alloc] initWithFormat:@"example"]; 
    testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a 
                withString:forString1a] mutableCopy]; 

为什么要在第一线的不可变的字符串,并在第二个是可变的字符串处理testedit目前尚不清楚。您根本不需要可变字符串,因为您正在用新字符串替换testedit

self.testedit = [[NSString alloc] initWithFormat:@"example"]; 
self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a 
                withString:forString1a] copy]; 

(你需要copy作为stringByReplacingOccurrencesOfString:withString:返回一个自动释放的对象,在这里你要保持它的保持)

的最后一块拼图是摆脱你的_testedit伊娃内存分配。在你的对象的dealloc方法做到这一点:

- (void) dealloc { 
    [_testEdit release]; 
    [super dealloc]; 
} 

(注意init,访问,并dealloc方法是三个地方,你应该使用属性语法参考伊娃。)

一切都很好,但是真的,你应该使用ARC!您很可能会以这种方式引入内存错误,而不是依赖编译器为您管理内存。

+0

你不需要使用'self.testedit = [[NSString alloc] initWithFormat:@“example”]; self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] copy];'。 'self.testedit = @“example”;'就够了。当你使用'@ properties'时,为什么你需要做一个'copy'?没有任何意义。 – iDev

+0

@ACB,我知道冗余,但我曾假定艾伯特把它作为一个更有意义的占位符。如果我缩写它,答案不会帮助解决这个问题。 Tx指出'copy'错误,已更正。 – foundry

0

由于您从不取消分配testedit,您将收到内存泄漏。每当你调用alloc时,这意味着你需要释放它。这通常意味着调用release

做这样的事情,而不是,那么一定要释放你分配的内存:

NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy]; 
+0

如何以及在哪里取消分配?我尝试添加'[testedit dealloc];'到NSTimer函数的末尾,应用程序崩溃了。 –

+1

在实现自己的dealloc方法时,除[super dealloc]之外不要直接调用-dealloc。除此之外,只有调用-release或-autorelease –

0

如果您使用ARC你不应该有问题。如果你不使用圆弧,可以试着加入autorelease

​​
+0

autorelease冻结和崩溃的应用程序。 –

1

我会建议你做的@property这里使用。

在.h文件中声明的属性为:

@property (nonatomic, retain) NSString *testedit; 
@property (nonatomic, retain) NSString *withString1a; 
@property (nonatomic, retain) NSString *forString1a; //if required write the @synthesize as well in .m class 

你可以写你的计时器方法:

-(void)myTimer { 

    self.testedit = @"example"; 
    self.withString1a = @"e";//this string gets its values randomly from an array in my real code 
    self.forString1a = @"flk34j";//this string gets its values randomly from an array in my real code 
    self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a]; 
} 

在dealloc方法,可以设置上述所有特性nilself.testedit = nil; )或者对他们做一个发布([testedit release];)。

如果可能,尝试切换到ARC,你不必担心内存管理。你的代码的问题是,你在使用大量的alloc/init语句之前不会释放变量。这会导致它失去该变量的引用,并且会泄漏它。你不需要那么多的分配语句。对于每个分配或保留,都应该有相应的释放/自动释放声明。

+0

我切换到ARC,我仍然有一些代码在我的巨大的应用程序内存泄漏,所以我只是通过手动管理一切。 –

+0

我会试试这个。我想知道如何摆脱那个黯淡的'mutableCopy' hehe –

+1

@AlbertRenshaw,你完全不需要'mutableCopy'。你应该使用'retain'来代替当前的代码。 – iDev