iOS 内存泄漏

Posted

技术标签:

【中文标题】iOS 内存泄漏【英文标题】:iOS Memory leaks 【发布时间】:2012-01-21 10:57:50 【问题描述】:

我已经读过,只有当该对象的保留计数变为零时,才会调用对象的 dealloc。

我在接口部分为UIColor 取一个对象并设置属性

UIColor *currentColor;
@property (nonatomic, retain) UIColor *currentColor;

在实现部分使用该对象后,我在dealloc中为该对象调用release方法

-(void)dealloc

    [currentColor release];
    [super dealloc];

我怀疑如何为这个对象调用dealloc,因为我不会在任何地方释放保留的对象。提前致谢。

【问题讨论】:

【参考方案1】:

我已经读过,只有在保留时才会调用对象的 dealloc 该对象的计数变为零。

是的。

为简单起见,将包含currentColor 对象的类称为ColorContainer。现在,如果您创建一个 ColorContainer 的实例,如下所示:

ColorContainer* containerColor = [[ColorContainer alloc] init]; // retain count + 1

containerColor 的保留计数变为 1。

假设您创建了一个UIColor 的实例并将该实例设置为currentColor 属性。在这种情况下,您可以采用两种不同的方式。 在第一个中,您可以创建一个如下所示的实例。如果你使用像initWithRed:green:blue:alpha: 这样的实例方法,你必须显式释放内存。

UIColor color* = [[UIColor alloc] initWithRed:0 green:0 blue:0 alpha:1]; // retain count + 1
containerColor.currentColor = color; // retain count +1, the referenced object has a retain count of 2 because you use a retain policy
[color release]; // retain count -1, now  the referenced object has a retain count of 1

在第二种方式中,您可以使用类方法(+ 符号)。在这种情况下,您不需要显式释放内存,因为在该类方法中创建的对象将在应用程序生命周期的某个时间点自动释放。

containerColor.currentColor = [UIColor whiteColor]; // retain count +1

现在假设你释放了containerColor 对象。如果 containerColor 的保留计数等于 1,则将其从使用它的对象中释放,它可以调用其 dealloc 方法,从而也解除 currentColor 引用的对象。

在这个简单的案例研究中,您必须注意,currentColor 引用的对象仅在其保留计数为 1 时才会从内存中完全删除(解除)。事实上,如果您这样做

UIColor color* = [[UIColor alloc] initWithRed:0 green:0 blue:0 alpha:1]; // retain count + 1
containerColor.currentColor = color; // retain count +1, the referenced object has a retain count of 2
//[color release];

你造成了内存泄漏(你明白吗?)。

总而言之,当您使用retaincopyinitnew(与alloc-init 相同)时,您必须始终调用他们的对应方releaseautorelease

根据经验,您需要始终平衡对象的保留计数以避免内存泄漏。

所以,作为一个比喻,你可以像一棵树一样思考记忆。假设您有一个父母 (containerColor) 和一个孩子 (currentColor)。如果父级(保留计数为 1)被释放,它会导致调用其 dealloc 方法并为其对象释放内存。如果在其 dealloc 方法中释放一个子项(保留计数为 1),则会调用其 dealloc 方法并释放内存。如果子项的保留计数大于 1,则会导致内存泄漏。

希望对你有帮助。

编辑

有关更多信息,您可以阅读About Memory Management。自 ios 5 以来,Apple 引入了 ARC。自动引用计数是一种编译器机制,它提供了 Objective-C 对象的自动内存管理。有关信息,请参阅Transitioning to ARC Release Notes。

【讨论】:

您好 Flex,非常感谢您的回答。【参考方案2】:

当您为 currentColor 属性使用保留设置器时,您 retain 该对象,如果您为对象使用 retaincopyalloc 内存,则必须释放它。 -(void)dealloc 是最好的地方

【讨论】:

【参考方案3】:

如果你分配了对象,你应该只调用release(通过alloccopyretain)。只要您正确处理它们,具有retain 属性的属性将自动为您执行内存管理,例如只能通过self.currentColor 访问它们。根据您创建颜色对象的方式,您可能会或可能不会使用release,但您始终应在您的 dealloc 方法中将该属性设置为 nil。两个例子:

// If you use this (or some other way to get the color without alloc, copy or retain)
// then you do not need to do any release
self.currentColor = UIColor.blackColor;
self.currentColor = [UIColor colorWithRed:1.0 green:0.5 blue:0.2 alpha:1.0];

// On the other hand if you get it like this, you have to release/autorelease the object
self.currentColor = [[UIColor alloc] initWithRed:1.0 green:0.5 blue:0.2 alpha:1.0];
[self.currentColor release];
// or better
self.currentColor = [[[UIColor alloc] initWithRed:1.0 green:0.5 blue:0.2 alpha:1.0] autorelease];

// dealloc always the same
-(void)dealloc
    [currentColor release], currentColor = nil;
    [super dealloc];

这里有两个重要的事实:

    对于您的代码问题的每个alloccopyretain,您必须发出releaseautorelease

    始终使用 self.currentColor 访问属性,而不是 currentColor,除非在解除分配时。这里的事情是,当使用self.currentColor 时,系统会自动添加内存管理代码。只要设置了self.currentColor,它就会自动retains 和releases 对象。只有在最终解除分配时,您才应该直接设置变量,有关更多信息,请参阅 this answer on the topic(感谢 Flex_Addicted)。

【讨论】:

在 dealloc 方法中调用 self.currentColor = nil; 可能会产生问题,如 release-or-set-to-nil-retained-members 和 MemoryMgmt Apple doc 中所建议的那样 谢谢,很有趣的想法。我会相应地编辑我的帖子。

以上是关于iOS 内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

iOS 内存泄漏的检测方式

内存泄漏,在do-catch块中。 iOS,Swift

如何修复 _NSCFNumber 的 iOS 内存泄漏?

iOS - AudioToolbox 内存泄漏

关于IOS内存泄漏

IOS性能调优系列:使用Instruments动态分析内存泄漏