如何在后台线程中处理ARC?

时间:2014-08-03 02:44:52

标签: ios objective-c multithreading memory-management automatic-ref-counting

我理解自动引用计数的工作原理:

在编译时,确定对象之间可能的关系类型,从而确定可能发生的版本,然后在运行时,跟踪每个对象的强指针引用数,并在该数字达到0时释放。至少在处理主线程时,我还没有在概念或实践中遇到过这方面的问题。

我注意到当我开始一个新的后台线程时,它不会释放任何生成的对象,直到线程结束。我举了一个例子:

enter image description here

本质上,在线程调用周围放置了一个自动的“@autoreleasepool”,因此显而易见的是,放置我自己的不会解决这个问题。事实上,我已经测试了相同的结果。如果我是正确的,那么强制池的存在正是导致我的问题,但我认为这是ARC可以在多线程应用程序上执行的最佳。内存使用缓慢而持续地倾斜。如果我将此线程留得太久,应用程序最终会耗尽内存。这是一个问题,因为线程需要能够在最坏的情况下无限期地运行。

我已经删除了线程中的一些主要分配。我相信我已经确定剩下的一些内存分配是从NSMutableArray释放的NSNumbers,因为我覆盖了它。

所以我想我必须做以下其中一项:

  1. 完全删除线程中的一致分配。
  2. 将应用更改为非ARC以在后台线程中手动释放内存。
  3. 检测内存何时高,保存线程状态,与主线程同步以释放对象,然后恢复算法。
  4. 找出是否存在某种方式通知主线程或ARC我希望对象同步以便它可以被释放。
  5. 意识到Apple实际上有一种方法可以调度ARC以异步方式正确处理另一个线程,并且从未在主参考页面上说出任何相关内容。
  6. 在包含分配对象(如字典)的文件中禁用ARC。 How can I disable ARC for a single file in a project?
  7. 这些看起来都不是解决我问题的方法,虽然我可以尝试1或6.有没有人有建议?

    更新:

    我运行了相同的算法但是在代码中添加了以下自动释放块,起初我认为我会反驳rmaddy和Aaron Brager的回应。

    -(void)setInt: (int)value For: (NSString *)variableName {
        @autoreleasepool {
            [self.intDictionary setValue:@(value) forKey:variableName];
        }
    }
    
    -(void)setBool: (bool)value For: (NSString *)variableName {
        @autoreleasepool {
            [self.boolDictionary setValue:@(value) forKey:variableName];
        }
    }
    

    以下是生成的内存分配图:

    enter image description here

    他们是对的。我很高兴在这种情况下我错了。这意味着我的编码将比我开始想象的容易得多。

1 个答案:

答案 0 :(得分:5)

自动释放的对象在其自动释放池耗尽时被释放。这通常发生在线程运行循环的末尾。

无论您是在谈论主线程还是后台线程,这种行为都是一样的。当然,它仅适用于不再具有强引用的对象。

对你的分析并不完全正确:

  

基本上,在线程调用周围放置了一个自动的“@autoreleasepool”,因此显而易见的是,放置我自己的不会解决这个问题。

考虑以下代码:

@autoreleasepool {
    for (int i = 0; i < 100000; i++) {
        // create an expensive autoreleased object
        // do something with it
    }
}

在这种情况下,当自动释放池耗尽时,直到运行循环结束时才会解除分配自动释放的对象。

但是,如果您添加自己的自动释放池:

@autoreleasepool {
    for (int i = 0; i < 100000; i++) {
        @autoreleasepool {
            // create an expensive autoreleased object
            // do something with it
        }
    }
}

对于for循环的每次迭代,当内池耗尽时,对象将被释放。

如果如上所示添加您自己的自动释放池无法解决您的问题,那么剩下的可能性是:

  1. 您正在使用ARC并且对象未被取消分配,因为它们仍然具有强大的参考(可能您有一个强大的参考周期)
  2. 内存使用量的增加不是来自Objective-C对象(例如,您创建了CGImageRef而从未调用CGImageRelease
  3. 你错误地没有在这个课程中使用ARC(你没有打电话给release
  4. 您提出的六个解决方案也可以解决问题,但修复起来可能更容易。