ARC 内存泄漏

Posted

技术标签:

【中文标题】ARC 内存泄漏【英文标题】:ARC memory leaks 【发布时间】:2012-04-03 22:34:54 【问题描述】:

我在配置为使用 ARC 的项目中遇到与 NSMutableArray 相关的内存泄漏,我认为它应该为您处理这些事情。

以下代码触发了 NSNumbers 的泄漏:

NSMutableArray *myArray = [[NSMutableArray alloc] init];

NSNumber  *myNumber = [NSNumber numberWithFloat:10];

[myArray addObject:myNumber];

运行最后一行在调试器中给出以下内容:

objc[1106]:__NSCFNumber 类的对象 0x765ffe0 自动释放,没有适当的池 - 只是泄漏 - 在 objc_autoreleaseNoPool() 上中断以进行调试

除此之外,对象似乎已正确添加到可变数组中,

我做错了什么吗?

注意:项目中有一个类我无法使用 ARC,因此我使用编译器标志 -fno-objc-arc 将其从 ARC 中排除。但是,泄漏正在使用 ARC 的其他类中发生。不确定这是否相关。

非常感谢您的帮助。

【问题讨论】:

这段代码是否在单独的线程上运行?还是在 @autoreleasepool 上下文之外的 main 方法中? 项目中唯一提到@autoreleasepool的是main.m。故障代码在其他类中。如何检查该方法是否在单独的线程上?我没有故意把它放到一个单独的线程上,但有可能已经发生了。我使用我在网上找到的音频单元基于一些非官方的示例代码构建了这个项目,所以我不确定所有的元素。 嗨,Richard,泄漏发生在主线程的单独线程上,在渲染音频单元的同一线程上,这是从弧中排除的类。有没有办法可以将进程重定向到主线程?还是您认为我应该重新尝试让音频单元渲染与 ARC 一起使用?非常感谢您的帮助,我想您已经指出了可能的原因! 我想我可以采取的另一条路线是使用编译器标志从 arc 中排除麻烦的类,并以老式的方式做事。你有什么建议吗?我没有经验所以想尽可能使用 ARC... 只要在线程开始执行的时候添加一个@autoreleasepool,就可以了…… 【参考方案1】:

您可能在后台线程上运行此代码,并且没有适当的自动释放池。 ARC 有时仍会为您自动释放对象,如果您调用 Apple 框架,它们可能仍然是非 ARC,因此它们绝对可能是自动释放对象。所以你仍然需要一个自动释放池。

Cocoa 在主线程上为您创建一个自动释放池,但在后台线程上不为您做任何事情。如果您要在不使用NSOperation 或其他东西的情况下将某些内容启动到后台线程,您需要将该线程包装在@autoreleasepool 中,如下所示:

- (void)doSomething 
    [self performSelectorInBackground:@selector(backgroundSomething)];


- (void)backgroundSomething 
    @autoreleasepool 
        NSLog(@"Here I am in the background, doing something.");
        myArray = [[NSMutableArray alloc] init];
        // etc.
    

【讨论】:

谢谢,确实是这个问题! 太好了,谢谢。 Instruments Leak 工具找不到这些,因为我猜它们在技术上不是泄漏。 关于 Cocoa 自动创建自动释放池的一些令人困惑的声明,我相信它可以工作,因为 main.m 模板在 int main(@autoreleasepool 嗯,Cocoa 也有一个单独的自动释放池,它会为主线程运行循环的每次传递创建。 @Maddy 如果您担心for 循环内的内存堆积,那么内部的自动释放池可能是合适的。在根级别设置一个仍然是明智的,只是为了避免任何泄漏。如果需要,您可以在其中嵌套额外的自动释放池。【参考方案2】:

您很可能已将 NSMutableArray 定义为静态变量。当您这样做时,您将超出任何自动释放池的范围,因为静态定义是在任何运行循环之外激活的。 ARC 并不神奇,它只是在现有保留/释放框架的框架内自动执行内存管理调用,因此在这些情况下无济于事。

解决方案是在类中的某处初始化静态变量,以便在运行循环中构建可变数组。

【讨论】:

不,静态变量不会导致内存泄漏,如果确实如此,那么我当前的项目中会有很多,我相信他只是在@autoreleasepool 上下文之外执行代码。 如果我将 NSMutableArray 定义为静态变量会是什么样子?数组是否应该在类头文件中声明,以及具有哪些属性?谢谢 这不是内存泄漏。至少不像大多数人定义的那样。几乎我在实践中遇到的在自动释放上下文之外执行代码的唯一方法是在静态变量中声明一个 NSObject - 我知道导致此确切消息的一种情况是在全局静态变量中声明一个带有 imageNamed 的静态 UIImage。 @Spin:它看起来像“静态 NSMutableArray *array = [[NSMutableArray alloc] init],但它会在类“实现”块之外。事实上,即使它不是静态的,只是一个在实现之外声明为全局的变量,它可能会导致同样的问题。我之前看过你的 EXACT 错误消息,所以我很确定这是你的问题......当你找到声明并修复它时,请标记我的答案正确,因为将否定答案标记为正确会非常有趣。 您好 Kendall,感谢您的建议,但 Richard 的回复解决了问题:需要围绕辅助线程设置自动释放池。

以上是关于ARC 内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

ARC 的内存泄漏

内存泄漏和僵尸有啥区别?

返回参数对象时 ARC 的内存泄漏

平铺 PDF 视图正在泄漏内存(非 ARC)

为啥迁移到 ARC 后我的应用程序充满了内存泄漏?

CALayer导致ARC内存泄漏