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)
最新文章
- uboot补丁的分析
- android fragment 的用法以及与activity的交互和保存数据的方法,包括屏幕切换(转载)!
- css小常识
- STL之分配器allocator
- ntfs安全权限和共享权限的区别
- 导入NGUI插件
- 无法连接到ASP.NET Development Server 解决办法
- EL字符串表达式和常用功能用途拦截
- Struts2文件的上传
- 旅行app(游记、攻略、私人定制) | 顺便游旅行H5移动端实例
- WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法
- 通过ZipKin整理调用链路
- sql里的正则表达式
- 转载 .Net多线程编程—并发集合 https://www.cnblogs.com/hdwgxz/p/6258014.html
- 开源RabbitMQ操作组件
- nowcoder 206A - Birthday - [最小费用最大流]
- 2-1:math库与random库
- Tornado 文件操作笔记
- HADOOP1.X中HDFS工作原理
- 【问题收集·中级】关于指示器自定义图片与UUID