这是释放内存的好方法吗?

9

我已经在iPhone上编程有一段时间了,对内存管理的经验不是很好。我想知道以下方法是否是释放内存的好方法。

int count = [someObject retainCount];

for (int i = 0; i < count; i ++) 
{
[someObject release];
}

在某些情况下(特别是在UIWebViews中),这种方法是一种绝望的举措。变量的保留计数被减少到零,这将释放它正在使用的内存。这个方法有点不太干净,但是它是否存在任何瓶颈?


5
不,这不是释放内存的好方法。 - Sneakyness
请尽快阅读苹果的内存管理文档,该文档解释了如何管理内存。千万不要这样做。 - user155959
6个回答

28
您不应该仅依赖于retainCount,因为iOS框架可能会保留对象。
请看下面是苹果公司对retainCount的声明:

重要提示:此方法通常无法帮助您调试内存管理问题。因为任何数量的框架对象都可能保留了一个对象以持有对它的引用,同时自动释放池可能会持有任意数量的延迟释放对象,因此您很难从此方法中获得有用的信息。

要了解您必须遵守的内存管理基本规则,请阅读“内存管理规则”。为了诊断内存管理问题,请使用适当的工具。

3
更不用说可能会有你自己的物体也在保留这个物体。无论是谁的物体,如果在某物仍然抓住它时你将其刺死,之后就会导致崩溃。 - Peter Hosey

14

这段代码是绝对不可取的。它只是掩盖了你的编程错误-而且做得很糟糕。

请学习正确的内存管理方法。没有替代品。

这里是内存管理编程指南,值得多读几遍。


7
正如其他人所提到的那样,-retainCount 几乎没有用。当你刚接触 Objective-C 的内存管理/引用计数时,有时会尝试使用 -retainCount 来帮助理解引用计数的工作原理,但实际上,这可能会在最好的情况下让人感到困惑。
你发布的代码本身可能是危险的,这取决于你使用 someObject 的周围环境。当应用于其他意外情况时,它也可能是危险的。以使用 @"a string" 编译指令创建的常量 NSString 为例:这些字符串被创建并设计永不释放。因此,像以下示例中那样应用你的代码将导致无限循环:
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString *string = @"theString";

    NSLog(@"retainCount == %lu", (unsigned long)[string retainCount]);

    for (NSUInteger i = 0; i < [string retainCount]; i++) {
        [string release];
    }

    [pool drain];
    return 0;
}

这将打印出以下内容:

2011-06-30 08:40:16.287 retainCount[35505:a0f] retainCount == 1152921504606846975

然后进入一个无限循环。

哦,我没有考虑到静态和单例模式 - 很棒的答案! - deanWombourne
我不会发布一个常数。我知道只有在new、alloc、copy和retain时才需要调用release。只是在某些情况下,一些对象的保留计数比我预期的要多。我发布的方法只是为那些少数情况下的解决方法。但从已发布的答案中,我想最好是跟踪为什么它被保留而不是使用那种方法:). - HG's
2
当涉及到保留计数时,“比我预期的多”并不意味着“不正确”。也不一定意味着有任何需要做的事情来降低它 - 只需确保你自己的职责得到处理,你自己的新/分配/保留/复制调用都与相应的(自动)释放平衡,并且一切都会很好。对于不属于您的对象,请记住 - 在NSVegas发生的事情,在NSVegas中留下。 :-) - Sherm Pendley
尝试使用[[NSNumber alloc] initWithInt: 3];进行相同的练习,然后定义“常量”的含义... - bbum

6
我强烈表示不能同意!
以下是您代码实例的示例:
// Create an autoreleased object
MyObject *myObject = [[[MyObject alloc] init] autorelease];

// Run your code to make it dealloc itself
int count = [myObject retainCount];
for (int i = 0; i < count; i ++)
    [myObject release];

你的代码将强制使myObject被释放。

然而,myObject也已经被放入自动释放池中-一旦该池开始释放其对象,你的应用程序将崩溃,因为myObject不再存在!

规则很简单:每次使用init、new或copy时都要调用release。否则,这不是你的问题。


这个答案最好的地方在于,你描述的问题甚至不是你的示例代码所遇到的问题。这就是为什么你应该依赖于引用计数规则(或自动引用计数或垃圾回收),而不是试图猜测框架的原因。 - user23743
我有点困惑 - 调用stringWithString会将myString添加到autorelease池中 - 这将在未来的某个时候尝试释放它。我错过了什么吗?(虽然要明确的是,我绝对不是说这是OP代码唯一的问题,这只是一个例子) - deanWombourne
+stringWithString: /*an instance of NSConstantString*/将只返回常量字符串,因此您实际上正在尝试释放静态对象。正如我所说,重要的是它是错误的:尝试聪明地处理它的错误只会以泪水收场。 - user23743
嘟囔嘟囔,我想你可能是对的;这只是我当时能想到的最清晰的方法将一个自动释放对象引入我的示例中!(但是我可以提出与您的评论相同的观点-我们不知道框架将来会如何处理这个问题 :) 我会修改我的答案!) - deanWombourne

3

不应该依赖于retainCount的值。您应该尽可能频繁地释放alloccopy

编辑:还有newretain


4
NARC...新分配、保留、复制。 - Dan Rosenstark


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接