【问题标题】:Objective C - ARC, memory management and performSelectorInBackground?Objective C - ARC,内存管理和 performSelectorInBackground?
【发布时间】:2014-08-12 04:38:46
【问题描述】:

ARC 是否不再需要在后台线程中调用的方法上使用@autoreleasepool?下面的代码假设会导致内存泄漏,除非 doStuff 使用 @autorelease 池进行包装,但是当我运行工具时,它显示 User 被分配并在 runloop 结束时被释放。

- (IBAction)buttonClicked:(id)sender {
    [self performSelectorInBackground:@selector(doStuff) withObject:nil];
}

- (void)doStuff {
    User *user = [[User alloc] init];
    NSLog(@"%@", user);
}

【问题讨论】:

  • 您的 user 实例不会自动释放,因此不会泄漏。 ARC 将在doStuff 方法的末尾添加对release 的显式调用。尝试使用自动释放的对象进行测试,例如 NSArray *array = [NSArray array];
  • 我试过 [NSArray 数组],不会造成泄漏
  • @aryaxt 为什么你认为它会泄露?您共享的代码中没有任何内容在 ARC 下有任何泄漏。
  • @CrimsonChris 我在文档中找不到任何说明 ARC 处理此问题的内容,因此暂时不想相信它
  • @aryaxt 这个结论是基于观察和假设它总是这样(每个操作系统、每个版本、每个设备、所有其他情况)。我不会在这么薄的冰上构建我的软件,尤其是文档另有说明。

标签: objective-c memory-management


【解决方案1】:

虽然可能在 NSThread 的实现中暗示了现有的自动释放池,但文档没有这样的保证。相反,文档明确指出:

performSelectorInBackground:withObject:

aSelector 表示的方法必须设置线程环境,就像您为程序中的任何其他新线程设置的那样。

Threading Programming Guide

如果您的应用程序使用托管内存模型 [MRC 和 ARC,而不是垃圾收集],那么创建自动释放池应该是您在线程进入例程中要做的第一件事。

结论:虽然在某些特定情况下可能存在自动释放池,但不建议依赖这一事实。这是未记录的行为,并且可以随着操作系统的每个版本或其他情况而改变。通常应避免在运输代码中使用。

【讨论】:

    【解决方案2】:

    我使用了以下测试应用:

    #import <UIKit/UIKit.h>
    @interface ViewController : UIViewController
    @end
    
    #import "ViewController.h"
    @implementation ViewController
    - (void)viewDidLoad{
        [super viewDidLoad];
        [self performSelectorInBackground:@selector(doStuff) withObject:nil];
    }
    - (void)doStuff {
        NSMutableArray *ar = [NSMutableArray array];
        for (int i=0; i<1000000; i++) {
            ar[i] = [NSString stringWithFormat:@"%i", i];
        }
    }
    @end
    

    使用分配工具对其进行分析,我得到以下结果:

    在调用树的第 8 行,使用了一个自动释放池,尽管我没有在我的代码中设置一个。另外,后台线程分配的内存似乎被释放了。
    因此,后台线程看起来好像安装了自动释放池。

    编辑(见下方评论):

    然而,这并不意味着没有必要为线程安装自动释放池,因为据我所知,上面显示的行为没有记录。

    【讨论】:

    • 虽然本身不​​是错误的,但这个答案在问题的意义上是误导性的(“ARC 不再需要 @autoreleasepool”)。
    • 我认为我的回答不会有误导性。但如果是这样,我会编辑它。
    • 您的回答使 OP 得出结论“好的,很好。所以最终的答案是自动为 ARC 下的新线程创建 autoreleasePool”(请参阅​​ cmets)。那是错误的。
    【解决方案3】:

    实际上,如果您不添加autorelease(这几乎只是自找麻烦),那么该代码应该会泄漏内存(在 MRC 下)。但无论如何我都会按照你的要求回答你的问题。

    ARC 应该消除对任何类型的内存管理的需要(除了块和 lot 的其他陷阱,但无论如何)。但是仍然有自动释放的对象。 @autoreleasepool 在紧循环等情况下特别有用。仍有池要排出,您不必自己将autorelease 添加到对象中。

    【讨论】:

    • 我无法让它导致内存泄漏
    • 无法获取导致内存泄漏的原因?在 ARC 下不会。
    • 想要内存泄漏?不要在 MRC 下释放分配的对象。达达。
    猜你喜欢
    • 2017-04-12
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多