Objective-C中的自动释放池
自动释放池块@autoreleasepool
自动释放池块在MRC和ARC下都可以使用。在MARC下,为了将自动释放池块内部的变量放入自动释放池,需要手动调用autorelease方法;在ARC下,只能通过声明变量为__autoreleasing来达到目的,而不是自动释放池块内部的所有变量,都会进入自动释放池。
加入在ARC下,有如下代码:
@autoreleasepool {
X *x = [[X alloc] init];
}
如果在Xcode控制台使用_objc_autoreleasePoolPrint()方法查看,会发现自动释放池没有任何变量。
但是如果我们进行如下调用:
@autoreleasepool {
X *x = [X create]; //create返回X类型对象
}
然后使用_objc_autoreleasePoolPrint()方法查看,会发现自动释放池里面持有X对象:
(lldb) po _objc_autoreleasePoolPrint()
objc[]: ##############
objc[]: AUTORELEASE POOLS for thread 0x1000aa5c0
objc[]: releases pending.
objc[]: [0x10100c000] ................ PAGE (hot) (cold)
objc[]: [0x10100c038] ################ POOL 0x10100c038
objc[]: [0x10100c040] 0x100509270 X
objc[]: ##############
0x70a40db675eb00e6
这个持有的X对象是因为调用的create方法不是以alloc/new/init/copy/mutableCopy开头命名,因此编译器在create方法返回前,会自动将返回的变量放入到自动释放池,而不是因为在自动释放池块内部声明了变量x导致的。
如果我们将变量x加上__autoreleasing属性,就看的很明白了,对象X在自动释放池中放入了两次:
(lldb) po _objc_autoreleasePoolPrint()
objc[]: ##############
objc[]: AUTORELEASE POOLS for thread 0x1000aa5c0
objc[]: releases pending.
objc[]: [0x103803000] ................ PAGE (hot) (cold)
objc[]: [0x103803038] ################ POOL 0x103803038
objc[]: [0x103803040] 0x102928700 X
objc[]: [0x103803048] 0x102928700 X
objc[]: ##############
0xb8c9f2d34f6300b0
将变量放入到自动释放池中,不会增加变量的引用计数
要看清这个问题,可以在MRC下将变量多次调用autorelease方法,然后使用CFGetRetainCount方法在Xcode控制台进行查看:
//MRC
@autoreleasepool {
X *x = [[X alloc] init];
[x autorelease];
[x autorelease];
[x autorelease];
}
控制台查看的结果如下,引用技术为1:
(lldb) p CFGetRetainCount((__bridge CFTypeRef)x)
(CFIndex) $ =
(lldb)
在ARC下,结论依然不变,但是更具迷惑性。
//ARC
@autoreleasepool {
X __autoreleasing *x = [[X alloc] init];
}
使用Xcode控制台查看,会发现变量X被放入了自动释放池,并且引用计数为1,符合预期:
(lldb) po _objc_autoreleasePoolPrint()
objc[]: ##############
objc[]: AUTORELEASE POOLS for thread 0x1000aa5c0
objc[]: releases pending.
objc[]: [0x104003000] ................ PAGE (hot) (cold)
objc[]: [0x104003038] ################ POOL 0x104003038
objc[]: [0x104003040] 0x10301c820 X
objc[]: ##############
0x3d01f52ffddf001a (lldb) p CFGetRetainCount((__bridge CFTypeRef)x)
(CFIndex) $ =
(lldb)
再看下面的代码:
//ARC
@autoreleasepool {
X __autoreleasing *x = [X create];//create返回X类型对象
}
在Xcode控制台查看,会发现x变量被放入了两次自动释放池,这是符合预期的,但是x变量的引用计数却变成了2,给人的感觉是没放入一次自动释放池,计数就加1:
(lldb) po _objc_autoreleasePoolPrint()
objc[]: ##############
objc[]: AUTORELEASE POOLS for thread 0x1000aa5c0
objc[]: releases pending.
objc[]: [0x106003000] ................ PAGE (hot) (cold)
objc[]: [0x106003038] ################ POOL 0x106003038
objc[]: [0x106003040] 0x1005176a0 X
objc[]: [0x106003048] 0x1005176a0 X
objc[]: ##############
0x4c2912a2a0dd00bc (lldb) p CFGetRetainCount((__bridge CFTypeRef)x)
(CFIndex) $ =
(lldb)
但是如果我们使用clang编译器的-S选项,将源码转换成汇编码,就会发现其中的奥秘:
.loc ## autorelease.m::
movq L_OBJC_CLASSLIST_REFERENCES_$_(%rip), %rsi
movq L_OBJC_SELECTOR_REFERENCES_.(%rip), %rcx
movq %rsi, %rdi
movq %rcx, %rsi
movq %rax, -(%rbp) ## -byte Spill
callq *_objc_msgSend@GOTPCREL(%rip)
.loc is_stmt ## autorelease.m:: 41行源码就是X __autoreleasing *x = [X create];
movq %rax, %rdi
callq _objc_retainAutoreleasedReturnValue ##这个Retain方法将返回的值被持有了一次,所以引用计数变成了2
movq %rax, %rdi
callq _objc_autorelease
leaq L__unnamed_cfstring_.(%rip), %rcx
movq %rax, -(%rbp)
在看下面这种情况,和上面的例子的效果一样:
//ARC
@autoreleasepool { X __autoreleasing *x1 = [X create];
X __autoreleasing *x2 = x1; }
在Xcode中查看输出,自动释放池里面有3个变量,符合预期,引用计数为3,符合预期:
(lldb) po _objc_autoreleasePoolPrint()
objc[]: ##############
objc[]: AUTORELEASE POOLS for thread 0x1000aa5c0
objc[]: releases pending.
objc[]: [0x102004000] ................ PAGE (hot) (cold)
objc[]: [0x102004038] ################ POOL 0x102004038
objc[]: [0x102004040] 0x100708950 X
objc[]: [0x102004048] 0x100708950 X
objc[]: [0x102004050] 0x100708950 X
objc[]: ##############
0xfbeaa82f2b80004a (lldb) p CFGetRetainCount((__bridge CFTypeRef)x1)
(CFIndex) $ =
(lldb)
查看汇编码可知:
.loc is_stmt ## autorelease.m:: 调用[X create]源码处
movq %rax, %rdi
callq _objc_retainAutoreleasedReturnValue ##第一处Retain方法
movq %rax, %rdi
callq _objc_autorelease
movq %rax, -(%rbp)
.loc is_stmt ## autorelease.m:: 复制x2 = x1处
movq -(%rbp), %rax
movq %rax, %rdi
callq _objc_retainAutorelease #第二处retain方法,这个方法retain的同时,将变量放入自动释放池
leaq L__unnamed_cfstring_.(%rip), %rcx
movq %rax, -(%rbp)
Objective-C中的自动释放池的更多相关文章
- (20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)
引用计数 引用计数是c/c++项目中一种古老的内存管理方式.当我8年前在研究一款名叫TCPMP的开源项目的时候,引用计数就已经有了. iOS SDK把这项计数封装到了NSAutoreleasePool ...
- OC 内存泄露 自动释放池
花絮:看到下面的代码就想起这么一个调侃: 一个老程序员,功成名就,金盆洗手不在写代码后,决定练练书法.提笔思索良久后在纸上写下:Hello world! /********************** ...
- (五十八)NSObject实现多线程、自动释放池的补充
模拟一个图片下载的场景,图片的下载需要2s,在这期间为了保证程序的流畅,应该把图片的下载放在子线程中进行. 使用NSObject的方法performSelectorInBackground方法即可实现 ...
- C++模拟OC的多重自动释放池
使用过OC的都知道,OC的引用计数机制用起来还比较方便.于是就仿照OC的形式搞了个C++引用计数. 支持多重自动释放池,每次autorelease都会放到栈顶的自动释放池中. 自动释放池也可以像变量一 ...
- 刀哥多线程自动释放池autoreleasepool
自动释放池 作用 自动释放对象的 所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动释放池中 自动释放池被销毁或者耗尽时,会向池中所有对象发送 release 消息, ...
- OC中对象元素的引用计数 自动释放池的相关概念
OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc] view plaincopy 1. // 2. / ...
- Objective c 自动释放池
学IOS 的大家都知道,IOS 一共有三种内存管理方式:MRC .ARC.自动释放池.我按照我个人的理解简述一下自动释放池,希望能给大家一点帮助,如有错误请大家及时批评指正. 自动释放池有几个特点:1 ...
- Autorelease自动释放池的使用
Autorelease自动释放池的使用 使用ARC开发,只是在编译时,编译器会根据代码结构自动添加了retain.release和autorelease. MRC内存管理原则:谁申请,谁释放 遇到al ...
- autoreleasepool自动释放池
示例: @autoreleasepool { ; i[largeNumber; i++) { (因识别问题,该行代码中尖括号改为方括号代替) Person *per = [[Person alloc ...
随机推荐
- Tomcat非root身份运行制作Linux系统服务管理
理论知识怱略,马上开始实战 一.首先准备好tomcat 启动.关闭.重启Shell脚本: 以下Shell脚本主要修改值 tomcatPath:tomcat目录 runUser:以哪个身份运行 此处测试 ...
- ES使用中的总结整理
最近项目中使用了ES搜索,开始时自己搭建了ES环境做测试,后面申请了公司的云平台应用, 对接ES的过程中颇具波折,遇到了很多问题,在这里统一整理记录下: 1,ES的9200 及 9300端口说明 92 ...
- idea生成实体类
1.点击View->Tool Windows->Database 2.点击Datebase框的加号,DateSource,选择对应的数据源,配置对应信息,点击Test Connection ...
- yum 安装 mongodb
1 .添加阿里源 vi /etc/yum.repos.d/mongodb.repo [mongodb-org] name=MongoDB Repository baseurl=http://mirro ...
- C# 两个进程之间通讯(管道通信 )
#region 客户端 NamedPipeClientStream pipeClient = new NamedPipeClientStream("localh ...
- 【转】有rand7(可以随机生成1到7的数据的随机函数),如何产生rand10(随机产生1-10的数)
今天停GJP说在面试的时候碰到了一道这样的题目:有rand7(可以随机生成1到7的数据的随机函数),如何产生rand10(随机产生1-10的数) 感觉很有意思,找到了这篇博客,感觉解法很好玩,转载在这 ...
- 谷歌浏览器安装 socketLog
第一步(本地浏览器安装调试扩展) 下载扩展包并解压 链接:https://pan.baidu.com/s/14df0ewl_3wjRHc8H1jsrWQ提取码:yyu1 打开谷歌浏览器,地址栏输入 c ...
- webDriver各版本对应
chromeDriver http://npm.taobao.org/mirrors/chromedriver/ http://chromedriver.storage.googleapis.com/ ...
- VC中MessageBox与AfxMessageBox用法与区别
一.MessageBox()用法 1.函数原型 Messagebox函数在Win32 API和MFC里的定义有区别. Win32 API的定义如下: int WINAPI MessageBox( ...
- leetcode 128最长连续序列
方法一:使用快排: //排序法,时间O(nlogn),使用STL,只是验证一下思想,非正解: class Solution { public: int longestConsecutive(vecto ...