在Swift程序中是否需要使用autoreleasepool?


95

WWDC14演示文稿的第17页,它说

使用Objective-C?仍然必须管理自动释放池
autoreleasepool {/ *代码* /}

那是什么意思?这是否意味着如果我的代码库中没有任何Objective-C文件,那autoreleasepool {}是不必要的吗?

回答一个相关问题时,有一个示例在其中autoreleasepool有用:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

如果上面的代码通过autoreleasepool拖放转换为Swift ,Swift是否足够聪明,知道number应该在第一个变量之后释放变量}(就像其他语言一样)?


1
autoreleasepoolSwift中似乎没有任何文档。我扩展了您的问题,并在开发论坛中提出了这个问题
亚伦·布拉格

Answers:


197

autoreleasepool在返回autorelease对象(由Objective-C代码或使用Cocoa类创建)时,在Swift中使用该模式。autoreleaseSwift中的模式非常类似于Objective-C中的模式。例如,考虑此方法的Swift实例化(实例化NSImage/ UIImage对象):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

如果您在Instruments中运行此代码,则会看到如下所示的分配图:

与autoreleasepool

但是,如果在没有自动释放池的情况下执行此操作,则会看到峰值内存使用率更高:

没有自动释放池

autoreleasepool就像在Objective-C中一样,它允许您显式管理何时在Swift中释放自动释放对象。

注意:处理Swift本机对象时,通常不会收到自动释放对象。这就是为什么演示文稿提到仅在“使用Objective-C”时需要此警告的原因,尽管我希望Apple在这一点上更加清楚。但是,如果要处理Objective-C对象(包括Cocoa类),则它们可能是自动释放对象,在这种情况下,Objective-C @autoreleasepool模式的这种Swift 表示法仍然有用。


2
在所有这些问题上,您可以编写自己的类,并println在in中进行处理deinit,并且可以轻松地精确地验证何时释放对象。或在仪器中观察它。为回答您的问题,看来Swift对象是从保留计数为+1的函数中返回的(不是自动释放对象),并且调用者将从那时起无缝管理所有权(例如,是否以及何时返回的对象超出范围,它会立即释放,而不是放置在autoreleasepool中)。
罗布

3
@StevenHernandez自动释放池与泄漏几乎没有关系。泄漏是由未释放的对象引起的。另一方面,自动释放池只是对象的集合,对于这些对象,释放将推迟到耗尽该池之前。池不控制某个对象是否被释放,而仅控制这种释放的时间。在地图视图中,您无法控制缓存的功能(使用内存,而不是真正的泄漏),如果存在真正的泄漏(并且我不知道任何重大的地图视图泄漏,尽管历史上一直存在,我也不会知道) UIKit中的随机,适度泄漏)。
罗布

2
@matt是的,我看到了类似的行为。因此,我重复了对NSImage/ UIImage对象的练习,并更加一致地表明了该问题(坦率地说,这是该问题的一个更常见的示例,因为峰值内存使用通常仅在处理较大的对象时才有问题;一个实际的例子可能是调整一堆图像大小的例程)。我还重现了调用Objective-C代码的行为,该行为明确创建了自动释放对象。不要误会我的意思:我认为我们在Swift中使用自动释放池的频率要比在Objective-C中更低,但是它仍然可以发挥作用。
罗布

1
我找到了一个可行的例子!只需pathForResource:ofType:反复致电NSBundle 。
马特2015年

1
我的pathForResource:ofType:示例在Xcode 6.3 / Swift 1.2中不再有效。:)
马特2015年

4

如果要在等效的Objective-C代码中使用它,则可以在Swift中使用它。

Swift将足够聪明,知道应该在第一个}之后释放number变量

仅在Objective-C可以的情况下。两者都遵循可可内存管理规则。

当然,ARC知道number在循环迭代结束时超出范围,并且如果保留了它,它将在那释放它。但是,这不能告诉您对象是否已自动释放,因为-[NSNumber numberWithInt:] 可能已经返回了一个自动释放的实例,也可能没有。您无法知道任何方法,因为您无权访问的来源-[NSNumber numberWithInt:]


1
如果Swift在此方面的行为与Objective-C相同,那么为什么演示文稿中提到“使用Objective-C?” 特别?
伊桑(Ethan)2014年

9
@Ethan看来,本机Swift对象不是autorelease对象,并且该autoreleasepool构造完全没有必要。但是,如果您的Swift代码正在处理Objective-C对象(包括Cocoa对象),则这些对象确实遵循自动释放模式,因此该autoreleasepool构造将变得有用。
罗布

我得到“自动释放池允许您明确管理在Swift中释放自动释放对象的时间”,但是我为什么要这么做?为什么编译器不能为我做?我必须添加自己的autoreleasepool,以防止VM在巨大的字符串操作的紧密循环中通过屋顶。对我来说明显的是应该在哪里添加它,并且效果很好。为什么编译器不能这样做?可以使编译器变得更聪明,以更好地完成它吗?
冯洛斯特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.