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 ...
随机推荐
- CSS层定位——固定定位,相对定位,绝对定位
主要写关于层定位的相关知识 ㈠定位概述 ⑴像图像软件中的图层一样可以对每一个layer能够精确定位操作 ⑵层定位的position属性决定了当前的一个网页元素,可以叠加到另一个网页元素上面,那么我们把 ...
- Java多线程和并发(十),JMM(Java内存模型)
目录 1.什么是JMM 2.JMM的主内存和工作内存 3.JMM如何解决可见性问题-指令重排序 4.Volatile 十.JMM(Java内存模型)(暂时没有理解) 1.什么是JMM 2.JMM的主内 ...
- RESTful规范与django编写restful接口
一.什么是RESTful规范 ①REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” ②REST从资 ...
- CentOS查看和修改PATH环境变量的方法
查看PATH:echo $PATH以添加mongodb server为列修改方法一:export PATH=/usr/local/mongodb/bin:$PATH//配置完后可以通过echo $PA ...
- scala实战学习-尾递归函数
求 $$ \Sigma\sideset{^b_a}f(x) $$ object sumfunc{ def sum(f: Int => Int)(a: Int)(b:Int): Int = { @ ...
- scala基础-1
函数式编程 并行编程 多核计算.云计算 引用透明,给值确定,结果也确定 数据类型 三种变量修饰符 val 定义immutable variable var 定义mutable va ...
- DVWA--Command Injection
首先我们查看源代码一下 <?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target = $_REQUEST[ 'ip' ]; / ...
- 数据加密之AES
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- Vagrant基本命令详解
正在学习Docker Swarm,接触到了Vagrant.Vagrant是一个创建虚拟机的技术,可以把它认为是一个Vmware,它让我们可以通过代码的方式快速地.可重复地创建针对不同虚拟环境的虚拟机, ...
- leetcode-easy-string-7 Reverse Integer
mycode class Solution(object): def reverse(self, x): """ :type x: int :rtype: int &qu ...