自动释放池块@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中的自动释放池的更多相关文章

  1. (20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)

    引用计数 引用计数是c/c++项目中一种古老的内存管理方式.当我8年前在研究一款名叫TCPMP的开源项目的时候,引用计数就已经有了. iOS SDK把这项计数封装到了NSAutoreleasePool ...

  2. OC 内存泄露 自动释放池

    花絮:看到下面的代码就想起这么一个调侃: 一个老程序员,功成名就,金盆洗手不在写代码后,决定练练书法.提笔思索良久后在纸上写下:Hello world! /********************** ...

  3. (五十八)NSObject实现多线程、自动释放池的补充

    模拟一个图片下载的场景,图片的下载需要2s,在这期间为了保证程序的流畅,应该把图片的下载放在子线程中进行. 使用NSObject的方法performSelectorInBackground方法即可实现 ...

  4. C++模拟OC的多重自动释放池

    使用过OC的都知道,OC的引用计数机制用起来还比较方便.于是就仿照OC的形式搞了个C++引用计数. 支持多重自动释放池,每次autorelease都会放到栈顶的自动释放池中. 自动释放池也可以像变量一 ...

  5. 刀哥多线程自动释放池autoreleasepool

    自动释放池 作用 自动释放对象的 所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动释放池中 自动释放池被销毁或者耗尽时,会向池中所有对象发送 release 消息, ...

  6. OC中对象元素的引用计数 自动释放池的相关概念

    OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc]  view plaincopy 1. //   2. / ...

  7. Objective c 自动释放池

    学IOS 的大家都知道,IOS 一共有三种内存管理方式:MRC .ARC.自动释放池.我按照我个人的理解简述一下自动释放池,希望能给大家一点帮助,如有错误请大家及时批评指正. 自动释放池有几个特点:1 ...

  8. Autorelease自动释放池的使用

    Autorelease自动释放池的使用 使用ARC开发,只是在编译时,编译器会根据代码结构自动添加了retain.release和autorelease. MRC内存管理原则:谁申请,谁释放 遇到al ...

  9. autoreleasepool自动释放池

     示例: @autoreleasepool { ; i[largeNumber; i++) { (因识别问题,该行代码中尖括号改为方括号代替) Person *per = [[Person alloc ...

随机推荐

  1. jmeter-响应有中文时,显示乱码

    Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

  2. [大数据] hadoop伪分布式安装

    注意:节点主机的hostname不要带"_"等字符,否则会报错. 一.安装jdk rpm -i jdk-7u80-linux-x64.rpm 配置java环境变量: vi + /e ...

  3. head first 设计模式笔记2-观察者模式:气象观测站

    设计原则:为了交互对象之间的松耦合设计而努力. 1.设计模式的一些理解 1)知道OO基础,并不足以让你设计出良好的OO系统 2)良好的OO设计必须具备可复用.可扩充.可维护三个特性 3)模式可以让我们 ...

  4. Python天天学_04_基础四

    Python_day_04 金角大王: http://www.cnblogs.com/alex3714/articles/5765046.html ------Python是一个优雅的大姐姐 学习方式 ...

  5. JDK_API剖析之java.util包

    Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结构. 一.接口 1.Collection<E> 接口 自1.2开始有 继承Iterable< ...

  6. vue路由 routers的写法:require用与不用

    vue路由的写法有很多种,这里我只说routers的写法,一种是compcomponent后面直接写路径,另一种是用require的方式,来看代码 import Vue from 'vue' impo ...

  7. AtCoder AGC036C GP 2 (组合计数)

    题目链接 https://atcoder.jp/contests/agc036/tasks/agc036_c 题解 终于有时间补agc036的题了. 这题其实不难的来着--我太菜了考场上没想出来 首先 ...

  8. A. Even Substrings

    A. Even Substrings time limit per test 0.5 seconds memory limit per test 256 megabytes input standar ...

  9. H5 video全屏与取消全屏兼容

    H5 video全屏与取消全屏各浏览器兼容,  requestFullscreen()全屏方法,exitFullscreen()退出全屏方法.兼容各个浏览器与css3兼容一样加个前缀即可. // 全屏 ...

  10. In an ASP.NET website with a codebehind at what point are the .cs files compiled?

    In an ASP.NET website with a codebehind at what point are the .cs files compiled? This applies to We ...