当前位置: 首页 > 编程日记 > 正文

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

引言

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

  • main函数中的autoreleasepool的作用?
  • 系统的autoreleasepool我们自己创建的autoreleasepool释放时机差别在哪?
  • 在ARC的环境中, 什么情况下需要使用autoreleasepool? 不使用autoreleasepool变量什么时候会被释放?

带着这三个问题, 一起进行一下下面的思考.

正文

对于autoreleasepool释放时机, 我们很容易在网上搜到这样的说法:

分两种情况:手动干预释放时机、系统自动去释放。

手动干预释放时机--指定autoreleasepool 就是所谓的:当前作用域大括号结束时释放。

系统自动去释放--不手动指定autoreleasepool

先不谈上面是否完全正确, 基于以上认知, 当时我灵光一闪推测main函数中autoreleasepool的作用可能为下面两种之一:

1.系统主线程中的默认的autoreleasepool.

2.整个App相对于iOS系统的一个autoreleasepool.

其他的解释其实在网上可以搜到很多, 所以这里我们可以做一个小实验.

第一点其实很好验证, 将main函数中的autoreleasepool注释掉, 运行

for (int i = 0; i < 10e5 * 2; i++) {NSString *str = [NSString stringWithFormat:@"hi + %d", i];
}
NSLog(@"finished!");复制代码

实际结果表明, 内存波动并没有什么区别:

  • 未注释Main函数中的autoreleasepool

  • 注释Main函数中的autoreleasepool

所以我们可以认为第二种是对的吗, 后来自己一想也觉得不对, 对于系统内存管理相关代码怎么会在程序里面呢, 不符合苹果的风格. 结果很明显我自己推测的都不对, 所以到底起什么作用呢? 待会再细说, 先验证一下释放时机的问题.

同样是上面一段函数, 在for循环中加入autoreleasepool:

for (int i = 0; i < 10e5 * 2; i++) {@autoreleasepool {NSString *str = [NSString stringWithFormat:@"hi + %d", i];}
}
NSLog(@"finished!");复制代码

我相信稍微了解一点的同学已经知道了运行结果:

为临时变量分配的内存已经得到平稳的释放, 所以结论就是最上面我们看到的认知? 其实本身每个Runloop已经默认会创建一个autoreleasepool了, 所以我们这里添加相当于嵌套(便于理解)了一个, 并没有弄清楚autoreleasepool自身的释放时机. 下面做另外一个小测试:

这一次在代码中新增对Runloop的Observer, 及时获取Runloop的状态变化确认释放时机, 代码如下:

// 添加一个监听者
- (void)addRunLoopObserver {// 1. 创建监听者CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"进入RunLoop");break;case kCFRunLoopBeforeTimers:NSLog(@"即将处理Timer事件");break;case kCFRunLoopBeforeSources:NSLog(@"即将处理Source事件");break;case kCFRunLoopBeforeWaiting:NSLog(@"即将休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"被唤醒");break;case kCFRunLoopExit:NSLog(@"退出RunLoop");break;default:break;}});// 2. 添加监听者CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
}复制代码

另外上面的方法运行连续运行两次, 不手动添加autoreleasepool, 大概是这样:

- (void)test1 {NSLog(@"test1 begin!");for (int i = 0; i < 10e5 * 2; i++) {//@autoreleasepool {NSString *str = [NSString stringWithFormat:@"hi + %d", i];//}}NSLog(@"test1 finished!");
}- (void)test2 {NSLog(@"test2 begin!");for (int i = 0; i < 10e5 * 2; i++) {//@autoreleasepool {NSString *str = [NSString stringWithFormat:@"hi + %d", i];//}}NSLog(@"test2 finished!");
}复制代码

运行之后的效果是这样的:

很清楚的看到Runloop没有完成一次循环之前所有内存都未释放, 即使局部变量出了作用域也必须等待Runloop循环完成.

下面同样, 手动添加autoreleasepool观察释放时机.

结果是意外也合理的. 即使Runloop未完成循环, 内存也即使释放了

总结

@autoreleasepool{}复制代码

等价于

void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);复制代码

每次出了{}时objc_autoreleasePoolPop()就被调用, 所以直接释放掉了. 当然, 系统自动创建的autoreleasepool也是一样, 只是调用的时机不同: 线程与Runloop是一一对应, Runloop与系统创建的autoreleasepool也是一一对应, 所以不论是Runloop完成了一次循环还是线程被关闭时, autoreleasepool都会释放, 当然手动添加的也会被管理, 上面为了方便理解, 说的是嵌套, 本质上是没有嵌套这个说法的, 对@autoreleasepool{}本质的一些个人总结:

主要就是一个类:AutoreleasePoolPage

两个函数: objc_autoreleasePoolPush()、objc_autoreleasePoolPop()

运作方式: autoreleasepool由若干个autoreleasePoolPage类以双向链表的形式组合而成, 当程序运行到@autoreleasepool{时, objc_autoreleasePoolPush()将被调用, runtime会向当前的AutoreleasePoolPage中添加一个nil对象作为哨兵,
在{}中创建的对象会被依次记录到AutoreleasePoolPage的栈顶指针,
当运行完@autoreleasepool{}时, objc_autoreleasePoolPop(哨兵)将被调用, runtime就会向AutoreleasePoolPage中记录的对象发送release消息直到哨兵的位置, 即完成了一次完整的运作.

另外根据官方文档:

Threads

If you are making Cocoa calls outside of the Application Kit’s main thread—for example if you create a Foundation-only application or if you detach a thread—you need to create your own autorelease pool......

主线程中的自动释放池是自动创建的, 文档中说子线程中的自动释放池是需要手动创建的, 但实测, 其实我们常用的多线程管理方式(GCD, NSOprationQueue, NSThread)都已经帮我们处理好了, 其中NSThread在iOS7之后才自动创建线程中的AutoreleasePool, 这个在官方文档中找不到记录, 参考StackOverflow: stackoverflow.com/questions/2…

另外网上有说法AutoreleasePool会影响性能, 其实看上面的函数运行的时间就可以发现, 并没有影响, 甚至加入了AutoreleasePool运行快了2秒(不严谨).

回到最初的问题, main函数中的autoreleasepool的作用, 我翻阅了大量资料, 在StackOverflow上赞的比较高的回答是没卵用... 暂且只能先这样认为了.. 希望有了解的同学可以讲解一下~

在实际中的使用场景其实很明确了, 在程序中中有大量临时变量的时候最好手动创建.

最常出现大量变量的时候显然是循环/遍历, 我们常用的for循环, 以及enumerate其实跟autoreleasepool也有关, for循环是不自动创建autoreleasepool的, 而enumerate中已经自动创建了autoreleasepool, 值得注意的是高并发enumerate常常会出一些意外的问题, 例如对象被提前释放, 所以建议高并发情况下使用for循环(性能高于enumerate), 再手动添加autoreleasepool.

本人前几篇文章中提到的一个App: 直播伴侣中就是手机端对弹幕进行高并发计算, 分词, 对比.. 使用了autoreleasepool之后明显在斗鱼弹幕服务器"炸鱼"时有所改善..欢迎Star: github.com/syik/Bullet…

相关文章:

QoS实验配置详解

QoS---CQ&#xff08;定制队列&#xff09;学习CQ&#xff08;定制队列&#xff09;的配置&#xff1b;本实验首先用ACL定义一些流量。然后再将这些流量进行先后排队&#xff0c;最后将排好队的流量策略应用到接口上 1 过滤流量R2(config)#access-list 101 permit ospf any any…

朴素贝叶斯分类器详解及中文文本舆情分析(附代码实践)

参加 2018 AI开发者大会&#xff0c;请点击 ↑↑↑作者 | 杨秀璋&#xff08;笔名&#xff1a;Eastmount&#xff09;&#xff0c;贵州财经大学信息学院老师&#xff0c;硕士毕业于北京理工大学&#xff0c;主要研究方向是Web数据挖掘、知识图谱、Python数据分析、图像识别等。…

计算机应用基础试题及答案试卷号7074,阅读文章,完成试题。后来才知道,在这千钧一发的时刻,是郝副营长划着了火柴,点燃了那本书,举得高高的, - 学进去中小学试卷试题库...

阅读《苏州园林》(节选)&#xff0c;回答问题。苏州园林(节选)叶圣陶①苏州园林据说有一百多处&#xff0c;我到过的不过十多处。其他地方的园林我也到过一些。倘若要我说说总的印象&#xff0c;我觉得苏州园林是我国各地园林的标本。②设计者和匠师们因地制宜&#xff0c;自出…

解决“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”...

[VS2005]解决“由于应用程序的配置不正确&#xff0c;应用程序未能启动&#xff0c;重新安装应用程序可能会纠正这个问题” 今天在准备发布用VS2005写的那个程序时&#xff0c;拷贝到我同事机器上&#xff0c;双击突然出现了“由于应用程序的配置不正确&#xff0c;应用程序未能…

PHP实时生成并下载超大数据量的EXCEL文件

最近接到一个需求&#xff0c;通过选择的时间段导出对应的用户访问日志到excel中&#xff0c; 由于用户量较大&#xff0c;经常会有导出50万加数据的情况。而常用的PHPexcel包需要把所有数据拿到后才能生成excel&#xff0c; 在面对生成超大数据量的excel文件时这显然是会造成内…

小学三年级上册计算机计划书,小学三年级班主任工作计划书

教学计划是教师个人制定的工作计划&#xff0c;通常为一个学期&#xff0c;内容主要包括制定教学计划的指导思想、教学内容以及教学目标&#xff0c;最重要的是每个教师要针对自己所带的学生特点来制定计划&#xff0c;因材施教才是对我们学生最好的教育.一、指导思想端正学习态…

10行代码爬取全国所有A股/港股/新三板上市公司信息

参加 2018 AI开发者大会&#xff0c;请点击 ↑↑↑作者 | 高级农民工本文已获原作者授权&#xff0c;如需转载&#xff0c;请联系原作者。摘要&#xff1a; 我们平常在浏览网页中会遇到一些表格型的数据信息&#xff0c;除了表格本身体现的内容以外&#xff0c;可能还想透过表格…

阿里云前端周刊 - 第 29 期

推荐 1. RESTful API 设计最佳实践 https://blog.philipphauer.de/... 项目资源的URL应该如何设计&#xff1f;用名词复数还是用名词单数&#xff1f;一个资源需要多少个URL&#xff1f;用哪种HTTP方法来创建一个新的资源&#xff1f;可选参数应该放在哪里&#xff1f;那些不涉…

Flash传值给asp页面

1.LoadVars的load方法&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;在flash中写一个拉出两个动态文件框&#xff0c;变量名为myName与myPsd&#xff0c;拉出一组件button&#xff0c;名为&#xff1a;submit_button&#xff0c;用于提交&#xff0c;再拉出一T…

《深度学习500问》,川大优秀毕业生的诚意之作

前端工程师掌握这18招&#xff0c;就能在浏览器里玩转深度学习基于知识图谱的人机对话系统 | 公开课笔记来呀&#xff01;AI喊你斗地主美团大脑&#xff1a;知识图谱的建模方法及其应用 | 公开课笔记60天,4位诺奖得主,他们将这样改造区块链程序员的江湖&#xff0c;务必掌握这些…

UC阿里鱼卡全网免流活动正在进行

UC&阿里鱼卡全网免流活动正在进行 优酷、虾米、高德、书旗应用专属流量免费 赠送100分钟国内通话、1G全国流量 扫码立即免费申请

普渡大学计算机硕士申请条件,普渡大学计算机与信息技术理学硕士研究生申请要求及申请材料要求清单...

2020年普渡大学计算机与信息技术理学硕士申请要求及普渡大学计算机与信息技术理学硕士申请材料要求清单是学生很感兴趣的问题&#xff0c;下面指南者留学整理2020年普渡大学计算机与信息技术理学硕士研究生申请要求及申请材料要求清单供大家参考。其中包括2020年普渡大学计算机…

object.ReferenceEquals(a,b)

code1 Assert.IsFalse(object.ReferenceEquals(10, 10));//比较时&#xff0c;要把比较的东西Box成Object&#xff0c;二个Ojbec地址是不一样的。 2 3 int value 10; 4 object one value; 5 object two value; 6 As…

深度文本匹配在智能客服中的应用

参加2018 AI开发者大会&#xff0c;请点击↑↑↑作者 | 云知声目录一. 深度文本匹配的简介1. 文本匹配的价值2. 深度文本匹配的优势3. 深度文本匹配的发展路线二. 智能客服的简介1. 智能客服的应用背景2. 智能客服的核心模块FAQ 库的构建语义召回相似度模型模型更新三. 深度文本…

计算机辅助焊接过程控制,重型车辆计算机辅助焊接工艺自动设计系统.pdf

金属学与金属工艺维普资讯第26卷 第10期 焊 接 学 报 v。1&#xff0e;26 N。&#xff0e;102005年 10月 TRANSACTIONSOFTHECHINAWELDINGINSTITUTION October 2005重型车辆计算机辅助焊接工艺 自动设计系统王克鸿&#xff0c; 韩 杰&#xff0c; 李 帅 王佳军(南京理工大学 材料…

Linux--文件管理以及权限的修改

一、文件属性查看ls -l filename 目录属性的大小&#xff08;文件名的字符总和&#xff09;-|rw-r--r--.|1| root| root| 46 |Oct 1 05:03 |filename— ————————— — ———— ———— —— ———————————— ———————— 1 …

Linux 之父归来!

参加2018 AI开发者大会&#xff0c;请点击↑↑↑作者 | 屠敏来源 | CSDN去修身养性的 Linux 之父 Linus Torvalds 在时隔一个余月后笑着归来&#xff0c;从曾临时接手 Linux 4.19 开发的稳定版维护者 Greg Kroah-Hartman 手中再次接过 Linux 内核开发的交接棒。这位向来天不怕地…

vscode断开调试服务器文件,vscode显示等待调试器断开连接

我正在尝试在vscode上调试量角器脚本。我编辑了launch.json文件,但是调试控制台抛出了下面的错误。vscode调试控制台输出:C:\Program Files\nodejs\node.exe --inspect-brk45448 conf.js C:\Users\abc\AppData\Roaming\npm\node_modules\protractor\example/conf.jsDebugger li…

深入理解Spring系列之六:bean初始化

《深入理解Spring系列之四&#xff1a;BeanDefinition装载前奏曲》中提到&#xff0c;对于非延迟单例bean的初始化在finishBeanFactoryInitialization(beanFactory)中完成。进入这个方法&#xff0c;代码如下。protected void finishBeanFactoryInitialization(ConfigurableLis…

webkit内核 css,纯CSS改变webkit内核浏览器的滚动条样式

基于webkit的浏览器现在可以自定义其滚动条的样式了&#xff0c;实现代码如下&#xff1a;复制代码代码如下:::-webkit-scrollbar/*整体部分*/{width: 10px;height:10px;}::-webkit-scrollbar-track/*滑动轨道*/{-webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2);border-rad…

数据依赖症:当今AI领域的核心风险

在最近结束的2017年度AI星际争霸竞赛上&#xff0c;Facebook做出了一款人工智能“CherryPi”&#xff0c;参与到这项旨在让各路AI技术在星际争霸游戏中同场竞技的赛事之中。 但很遗憾的是&#xff0c;Facebook仅仅获得了赛事的第六名&#xff0c;最直接的原因&#xff0c;在于F…

1024程序员节,你是我们要找的那条锦鲤吗?

参加2018 AI开发者大会&#xff0c;请扫描海报二维码 叮咚&#xff0c;您有一封 #1024吐槽狂欢派对# 邀请函请查收。 ▌什么是程序员&#xff1f; 全员格子、黑框眼镜&#xff0c;还是等于创造力忍耐力&#xff1f; 刻板标签、思维定式&#xff0c;还是高阶自黑玩梗幽默&#…

虚拟机管理你的服务器,全面解析VMware的虚拟机管理解决方案

本教程将为你讲述VMware的虚拟机管理解决方案&#xff0c;说起虚拟机&#xff0c;VMware绝对可以算的上是个中翘楚了&#xff0c;并且VMware的虚拟桌面结构解决方案可以起到增强管理效率&#xff0c;降低成本等等效用&#xff0c;话不多说&#xff0c;这就为大家介绍。Vmware的…

针对抓win2003系统密码的诡计

命令行下卸载win2003 sp1/sp2 %systemroot%\$NtServicePackUninstall$\spuninst\spuninst /U 按无人参与模式删除 service pack。如果使用此选项&#xff0c;那么在卸载 SP1 的过程中&#xff0c;只有出现致命错误才会显示提示。 /Q 按安静模式删除 SP1&#xff0c;此模式与无人…

那个曾经为美国NASA开发火星大脑的AI公司,现在和华为合作了

2010 年&#xff0c;美国航天航空局 NASA 敲响了一家创业公司的大门&#xff0c;希望他们参与火星探测器“大脑”的研发项目。这家公司就是 Neurala&#xff0c;一家专注于深度学习技术的波士顿初创公司。 NASA 的要求是一个艰难的挑战&#xff0c;因为火星探测器自身计算能力…

艾伦人工智能研究院开源AllenNLP,基于PyTorch轻松构建NLP模型

艾伦人工智能研究院&#xff08;AI2&#xff09;开源AllenNLP&#xff0c;它是一个基于PyTorch的NLP研究库&#xff0c;利用深度学习来进行自然语言理解&#xff0c;通过处理低层次的细节、提供高质量的参考实现&#xff0c;能轻松快速地帮助研究员构建新的语言理解模型。 Alle…

3650服务器性能,全新联想System x3650 M4服务器性能出色

系统支持Microsoft Windows Server 2008 R2Microsoft Windows Server 2008&#xff0c;Datacenter x64 EditionMicrosoft Windows Server 2008&#xff0c;Datacenter x86 EditionMicrosoft Windows Server 2008&#xff0c;Enterprise x64 EditionMicrosoft Windows Server 20…

不只翻译机,搜狗将在半年内推数款智能硬件产品

10月24日已是昨日&#xff0c;但属于开发者的1024一直都在——2018 AI开发者大会就是你的1024。11月8-9日&#xff0c;现场聆听国内外AI大牛的深知灼见&#xff0c;与工业界AI应用思维紧密同步&#xff0c;收获60技术大咖的干货分享。扫码填写大会注册信息表&#xff0c;就有可…

Windows Embedded Standard开发初体验(四)

添加文件、依赖组件、注册表 接下来我们就要进入创建组件最重要的一环了&#xff0c;添加文件。为什么说重要&#xff0c;因为这里有一个大坑&#xff0c;我在Windows Embedded Standard产品组施卫娟老师的指导下&#xff0c;花了两周的时间才勉强爬出来&#xff0c;可见该坑之…

Windows 2003 + ISA 2006+单网卡×××配置(4)

&#xff08;接上&#xff09;图13 然后下一步&#xff0c;用户集默认所有用户&#xff0c;不用改变&#xff0c;直接下一步&#xff0c;完成&#xff0c;然后会出现如图14图14照样还是点击应用。。。好了&#xff0c;都配置完了&#xff0c;下面我们做个测试。。。我本机的IP地…