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

Tim*_*wan 3 multithreading memory-management objective-c ios automatic-ref-counting

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

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

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

在此输入图像描述

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

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

所以我想我将不得不做以下其中一件事:

  1. 完全删除线程中的一致分配.
  2. 将应用程序更改为非ARC以在后台线程中手动释放内存.
  3. 检测内存何时高,保存线程状态,与主线程同步以释放对象,然后恢复算法.
  4. 找出是否存在某种方式通知主线程或ARC我想要一个对象同步,以便它可以被释放.
  5. 意识到Apple实际上有一种方法来调度ARC以正确地异步处理另一个线程,并且从未在主参考页面上说出任何相关内容.
  6. 在具有分配对象(如字典)的文件中禁用ARC.如何为项目中的单个文件禁用ARC?

这些看起来都不是解决我问题的方法,尽管我可能会尝试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];
    }
}
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

Aar*_*ger 5

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

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

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

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

考虑以下代码:

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

在这种情况下,当自动释放池耗尽时,所有自动释放的对象都不会被释放,直到运行循环结束.

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

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

对于循环的每次迭代,当内池排空时,对象将被释放for.

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

  1. 您正在使用ARC,并且对象未被取消分配,因为它们仍然具有强大的引用(可能您具有强大的引用周期)
  2. 内存使用量的增加不是来自Objective-C对象(例如,您创建了一个CGImageRef并且从未调用过CGImageRelease)
  3. 你错误地没有在这个班级使用ARC(你没有打电话release)

您提出的六个解决方案也可以解决问题,但修复起来可能更容易.