【发布时间】:2014-09-25 21:24:53
【问题描述】:
我了解自动引用计数的工作原理:
在编译时,确定对象之间可能的关系类型以及可能发生释放的位置,然后在运行时跟踪对每个对象的强指针引用的数量,并在该数量达到 0 时释放。至少在处理主线程时,我在概念上或实践中都没有遇到过这个问题。
我注意到当我启动一个新的后台线程时,它不会释放任何生成的对象,直到线程结束。我跑了一个例子:
本质上,在线程调用周围放置了一个自动的“@autoreleasepool”,所以很明显,放置我自己的不会解决这个问题。事实上,我已经用相同的结果进行了测试。如果我在这方面是正确的,那么该强制池的存在正是导致我的问题的原因,但我认为这是 ARC 可以在多线程应用程序上执行的最佳操作。内存使用缓慢且持续地倾斜。如果我离开这个线程太久,应用程序最终会耗尽内存。这是一个问题,因为线程需要能够在最坏的情况下无限期地运行。
我已经删除了线程中的一些主要分配。我相信我已经确定一些剩余的内存分配是从 NSMutableArray 释放的 NSNumber,因为我正在覆盖它。
所以我想我必须执行以下操作之一:
- 完全删除线程中的一致性分配。
- 将应用更改为非 ARC 以在后台线程中手动释放内存。
- 检测内存高时,保存线程状态,与主线程同步释放对象,然后恢复算法。
- 了解是否有某种方法可以通知主线程或 ARC 我想要同步对象以便释放它。
- 意识到 Apple 实际上有一种方法可以调度 ARC 以正确地异步处理另一个线程,并且从未在主要参考页面上提及它。
- 在具有分配对象的文件(例如字典)中禁用 ARC。 How can I disable ARC for a single file in a project?
这些看起来都不是我的问题的完美解决方案,尽管我可能会尝试 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];
}
}
这是生成的内存分配图:
他们是正确的。我很高兴在这种情况下我错了。这意味着我的编码将比我开始想象的要容易得多。
【问题讨论】:
-
我建议在仪器中使用僵尸分析器来确定未发布的内容。此外,如果您提供一些与您的后台线程实现相关的代码,这将对(我)有所帮助。
-
这一切都与线程无关。你只是碰巧在你的后台线程上创建了很多自动释放的对象。只需在适用的情况下添加
@auoreleasepool的其他用途。 -
@rmaddy ...这似乎也与ARC关系不大。
-
@rmaddy 抱歉,这行不通。整个线程调度已经在一个池中。添加嵌套池不会覆盖它。即使可以,我也需要从字典中动态释放额外的对象,我不会在同一个块中创建和释放它们,而不首先离开该块不确定的次数。
-
@rmaddy 啊,你实际上是对的,maddy。显然,内部调用是受青睐的,即使之前分配了一些东西,它也可能在块的末尾被释放。参考图片更新。
标签: ios objective-c multithreading memory-management automatic-ref-counting