【问题标题】:Is this a good way to release memory?这是释放内存的好方法吗?
【发布时间】:2011-09-25 22:47:17
【问题描述】:

我在 iPhone 上编程已经有一段时间了,在内存管理方面有过糟糕的经历。我想知道以下方法是否是释放内存的好方法。

int count = [someObject retainCount];

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

这种方法在我遇到的一些情况下(尤其是UIWebViews)是一种绝望的行为。变量的 retainCount 减少到零,这将释放它正在使用的内存。该方法有点脏,但是否存在与之相关的瓶颈?

【问题讨论】:

  • 不,这不是释放内存的好方法。
  • 请尽快阅读 Apple 的内存管理文档,其中解释了您如何管理内存。永远不要这样做。

标签: iphone objective-c memory-management


【解决方案1】:

您不应该依赖retainCount,因为iOS 框架有可能保留对象,

阅读下面 Apple 对retainCount 的评价

重要提示:这种方法通常是 调试内存没有价值 管理问题。因为任何数 的框架对象可能已保留 一个对象以保存引用 对它,同时 自动释放池可能持有任何 延迟发布的数量 反对,你不太可能 可以从中得到有用的信息 方法。

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

【讨论】:

  • 更不用说您自己的一个对象也保留该对象的可能性。它是谁的对象并不重要;如果你在物体仍然抓住它的时候将它刺死,你稍后会导致崩溃。
【解决方案2】:

此代码绝对是禁止。它只是隐藏了你的编程错误——而且这样做的方式非常糟糕。

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

这里是memory management programming guide。值得一读。

【讨论】:

    【解决方案3】:

    正如其他人所提到的,-retainCount 几乎没用。当您不熟悉 Objective-C 中的内存管理/引用计数时,有时会很想尝试使用 -retainCount 来帮助理解引用计数的工作原理,但实际上,它可能(看似)令人困惑最好的。

    您发布的代码本身就具有潜在危险,具体取决于您使用 someObject 的环境。当应用于您未预料到的其他情况时,它也可能很危险。以使用@"a string" 编译器指令创建的常量NSStrings 为例:这些字符串被创建并且设计为永远不会被释放。所以像下面的例子那样应用你的代码会导致一个无限循环:

    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

    然后进入无限循环。

    【讨论】:

    • 哦,我没想到静态和单例 - 好答案!
    • 我不会释放常量。我知道只需要为 new、alloc、copy 和 retain 调用该版本。只是在某些情况下,某些对象的保留计数超出了我的预期。我发布的方法只是针对这少数情况的一种解决方法。但从发布的答案中,我想最好追查为什么保留它而不是使用该方法:)。
    • 在保留计数方面,“超出我的预期”并不意味着“不正确”。也不一定意味着需要做任何事情来降低它 - 只要确保你自己的责任得到照顾,你自己的 new/alloc/retain/copy 调用都与相应的 (自动)释放,一切都会好起来的。对于您以外的对象,请记住 - 在 NSVegas 中发生的事情会留在 NSVegas 中。 :-)
    • 尝试与[[NSNumber alloc] initWithInt: 3]; 相同的练习,然后定义“常量”的含义......
    【解决方案4】:

    我不能说不足够强调!

    以你的代码为例:

    // 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。否则不是你的问题。

    【讨论】:

    • 这个答案最好的一点是您描述的问题甚至不是您的示例代码所存在的问题。这就是为什么您应该依赖引用计数规则(或自动引用计数或垃圾回收)而不是试图对框架进行事后猜测。
    • 我很困惑——对 stringWithString 的调用会将 myString 添加到自动释放池中——这将在未来的某个时候尝试释放它。我错过了什么? (虽然要清楚,但我绝对不是说这是 OP 代码存在的唯一问题,这只是一个示例)
    • +stringWithString: /*an instance of NSConstantString */ 只会返回常量字符串,因此您实际上是在尝试释放静态对象。正如我所说,重要的部分是它是错误的:试图聪明地知道它的错误只会以泪水告终。
    • grumble grumble 我想你可能是对的;这只是我当时能想到的将自动释放的对象放入我的示例的最清晰方法! (但我可以就你的评论提出同样的观点——我们不知道框架将来会如何处理这个问题:)我会改变我的答案!
    【解决方案5】:
    【解决方案6】:

    您不应依赖retainCount 的值。您应该尽可能频繁地发布alloccopy

    编辑:newretain

    【讨论】:

    • NARC...新分配保留副本
    猜你喜欢
    • 1970-01-01
    • 2014-07-04
    • 2013-07-14
    • 1970-01-01
    • 2019-02-11
    • 2012-06-02
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多