Swift 在内存管理上使用的是自动引用计数 (ARC) 的一套方法,在 ARC 中虽然不需要手动地调用像是 retainrelease 或者是 autorelease 这样的方法来管理引用计数,但是这些方法还是都会被调用的 -- 只不过是编译器在编译时在合适的地方帮我们加入了而已。其中 retain 和 release 都很直接,就是将对象的引用计数加一或者减一。但是autorelease 就比较特殊一些,它会将接受该消息的对象放到一个预先建立的自动释放池 (auto release pool) 中,并在 自动释放池收到 drain 消息时将这些对象的引用计数减一,然后将它们从池子中移除 (这一过程形象地称为“抽干池子”)。

在 app 中,整个主线程其实是跑在一个自动释放池里的,并且在每个主 Runloop 结束时进行 drain操作。这是一种必要的延迟释放的方式,因为我们有时候需要确保在方法内部初始化的生成的对象在被返回后别人还能使用,而不是立即被释放掉。

在 Objective-C 中,建立一个自动释放池的语法很简单,使用 @autoreleasepool 就行了。如果你新建一个 Objective-C 项目,可以看到 main.m 中就有我们刚才说到的整个项目的 autoreleasepool:

int main(int argc, char * argv[]) {@autoreleasepool {int retVal = UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate class]));return retVal;}
}

更进一步,其实 @autoreleasepool 在编译时会被展开为 NSAutoreleasePool,并附带 drain方法的调用。

而在 Swift 项目中,因为有了 @UIApplicationMain,我们不再需要 main 文件和 main 函数,所以原来的整个程序的自动释放池就不存在了。即使我们使用 main.swift 来作为程序的入口时,也是不需要自己再添加自动释放池的。

但是在一种情况下我们还是希望自动释放,那就是在面对在一个方法作用域中要生成大量的 autorelease 对象的时候。在 Swift 1.0 时,我们可以写这样的代码:

  func loadBigData() {if let path = NSBundle.mainBundle().pathForResource("big", ofType: "jpg") {for i in 1...10000 {let data = NSData.dataWithContentsOfFile(path, options: nil, error: nil)NSThread.sleepForTimeInterval(0.5)}}}

dataWithContentsOfFile 返回的是 autorelease 的对象,因为我们一直处在循环中,因此它们将一直没有机会被释放。如果数量太多而且数据太大的时候,很容易因为内存不足而崩溃。在 Instruments 下可以看到内存 alloc 的情况:

这显然是一幅很不妙的情景。在面对这种情况的时候,正确的处理方法是在其中加入一个自动释放池,这样我们就可以在循环进行到某个特定的时候施放内存,保证不会因为内存不足而导致应用崩溃。在 Swift 中我们也是能使用 autoreleasepool 的 -- 虽然语法上略有不同。相比于原来在 Objective-C 中的关键字,现在它变成了一个接受闭包的方法:

func autoreleasepool(code: () -> ())

利用尾随闭包的写法,很容易就能在 Swift 中加入一个类似的自动释放池了:

func loadBigData() {if let path = NSBundle.mainBundle().pathForResource("big", ofType: "jpg") {for i in 1...10000 {autoreleasepool {let data = NSData.dataWithContentsOfFile(path, options: nil, error: nil)NSThread.sleepForTimeInterval(0.5)}}}
}

这样改动以后,内存分配就没有什么忧虑了:

这里我们每一次循环都生成了一个自动释放池,虽然可以保证内存使用达到最小,但是释放过于频繁也会带来潜在的性能忧虑。一个折衷的方法是将循环分隔开加入自动释放池,比如每 10 次循环对应一次自动释放,这样能减少带来的性能损失。

其实对于这个特定的例子,我们并不一定需要加入自动释放。在 Swift 中更提倡的是用初始化方法而不是用像上面那样的类方法来生成对象,而且从 Swift 1.1 开始,因为加入了可以返回 nil 的初始化方法,像上面例子中那样的工厂方法都已经从 API 中删除了。今后我们都应该这样写:

let data = NSData(contentsOfFile: path)

使用初始化方法的话,我们就不需要面临自动释放的问题了,每次在超过作用域后,自动内存管理都将为我们处理好内存相关的事情。

@AUTORELEASEPOOL相关推荐

  1. 在ARC环境中autoreleasepool(runloop)的研究

    引言 最近有个大佬考察了我关于autoreleasepool的了解, 之前一直认为自己了解, 但是稍微一问深, 自己却哑口无言. 仔细思考了下, 决定要将这个问题结合之前的知识从新梳理一下, 当然, ...

  2. iOS之深入解析自动释放池autoreleasepool的底层原理

    一.自动释放池 autoreleasepool 原理 自动释放池是 OC 中的一种内存自动回收机制,它可以将加入 autoreleasePool 中的变量 release 的时机延迟. 简单来说,就是 ...

  3. Cocos2d-x 3.x:如何进行合理的内存分配(使用AutoreleasePool 来合理的管理内存)

    Cocos2d-x 3.x:如何进行合理的内存分配(使用AutoreleasePool 来合理的管理内存) 本文转载至深入理解Cocos2d-x 3.x:如何进行合理的内存分配 设想如下场景,这是一个 ...

  4. autoreleasepool底层探索

    #自动释放池初探 修改main.m里的代码如下: int main(int argc, const char * argv[]) {@autoreleasepool {}return 0; } 复制代 ...

  5. [iOS开发]@autoreleasepool原理探究

    自动释放池 自动释放池 @autoreleasepool 最常见的地方就是我们项目的 main函数 .我们今天来深入探索下其底层结构和实现原理.先查看一下编译后的情形: int main(int ar ...

  6. AutoReleasePool 底层原理

    概念 AutoreleasePool(自动释放池)是OC中的一种内存自动回收机制,它可以延迟加入AutoreleasePool中的变量release的时机.在正常情况下,创建的变量会在超出其作用域的时 ...

  7. 子线程是否要手动创建autoreleasepool

    NSThread和NSOperationQueue开辟子线程需要手动创建autoreleasepool,GCD开辟子线程不需要手动创建autoreleasepool,因为GCD的每个队列都会自行创建a ...

  8. AutoreleasePool的实现

    原文链接AutoreleasePool的实现 在MRC中,调用[obj autorelease]来延迟内存的释放:在ARC下,对象调用autorelease方法,就会被自动添加到最近的自动释放池,只有 ...

  9. iOS错误总结 “instance variable '******' accessed in class method”以及“autoreleasepool的用处

    1,instance variable '******' accessed in class method 比如: @interface MyClass : NSObject{int number;} ...

最新文章

  1. 利用Linux命令行进行文本按行去重并按重复次数排序yes
  2. Spring + hibernate + JPA 配置
  3. Android天气预报设计
  4. 【CodeForces - 518D】Ilya and Escalator(概率dp,数学期望)
  5. python内存池机制_python的内存管理机制
  6. transforms.Compose()函数
  7. c语言程序设计省考是什么,省考C语言程序设计题附答案..doc
  8. 北京最值得逛的50个地方:后海、798、簋街...
  9. linux重置电池阀值,Thinkpad在linux(ubuntu)下修改电池充电阈值,成功解决Thinkpad在Linux下的电池充电问题...
  10. 3d之家开机号计算机网,3d之家最新开机号
  11. HiJson,一个json格式化查看工具
  12. linux scp传输文件权限被拒绝,Linux的远程传输文件scp及出现Permission denied (publickey).lost connection问题解决方法-Go语言中文社区...
  13. matlab锯齿交换,MATLAB折线消除锯齿平滑
  14. 首届·技术播客月开播在即
  15. 图片img或者含有img元素拖拽时的阴影效应问题
  16. JAVA计算机毕业设计网课系统(附源码、数据库)
  17. OC面向对象的三大特征(封装 继承 多态)习题2 复合
  18. vscode 安装cnpm出现cnpm : 无法加载文件 C:\Users\代码\AppData\Roaming\npm\cnpm.ps1
  19. 【2014 年末岁首】
  20. 泰戈尔《世界上最远的距离》

热门文章

  1. 西农大许金荣课题组在小麦赤霉病研究领域取得重要突破
  2. UCL葡萄酒(red white wine quality)数据集字段解释、数据导入实战
  3. R语言单变量分析实战:汇总统计(Summary Statistics)、频率表(Frequency Table)、图表(charts: boxplot、histogram、density)
  4. R语言使用geompointdensity包的geom_pointdensity函数将散点图和密度图结合起来、使用viridis包的scale_color_virdis函数为密度数据添加调色板色彩渐变
  5. R语言ggplot2可视化水平条形图的标题(title)、副标题(subtitle)和图片说明信息(caption)左对齐实战
  6. R语言使用pROC包在同一图中绘制两条ROC曲线并通过假设检验检验ROC曲线的AUC或者偏AUC的差异(输出p值)
  7. R密度聚类之DBSCAN模型
  8. airpods固件更新方法_AirPods如何升级固件?AirPods更新固件方法教程
  9. c语言1余3,c语言1—3真题(含答案).ppt
  10. 《LoadRunner 没有告诉你的》之三——理发店模型