自动释放池块@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. 将springboot jar应用打包成镜像并在docker运行成容器

    先看一下我的Dockerfile内容与服务器中的目录结构 上面 yibai-0.0.1-SNAPSHOT.jar 为springboot应用打成的jar包,Dockerfile为将应用打成镜像的配置文 ...

  2. C# 之抽象类

    抽象类 抽象类中 .只包含抽象方法, .包含非抽象方法和抽象方法 .可使用get和set访问器 Example : public abstract class GeeksForGeeks { publ ...

  3. (转)Spring实例化

    标签:SpringContextUtil,getBean 手动获取Bean 方法一  不用配置xml,直接java代码实现 /** * 工厂模式选择Bean类 */ public class MyBe ...

  4. Android的SQLite基本操作

    涉及SQLite的增删改查,结果用log显示 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...

  5. iview之avatar组件

    avatar组件是一个获取网络路径图片的组件 它再vue中使用的话build时不会被打包,路径仍然为原来的路径 所以相对路径不会有效 如下: <Avatar style="margin ...

  6. Java——流、文件与正则表达式

    0. 字节流与二进制文件 我的代码 package javalearn; import java.io.DataInputStream; import java.io.DataOutputStream ...

  7. leetcode-easy-string-14 Longest Common Prefix

    mycode   91.59% class Solution: def longestCommonPrefix(self, strs: List[str]) -> str: if not str ...

  8. [Java]使用正则表达式实现分词

    手工分词稍嫌麻烦,不好维护,而利用正则表达式就利索多了.Java提供了java.util.regex.Matcher,java.util.regex.Pattern类来帮助我们实现此功能. 例一:以下 ...

  9. day7_集合,深浅copy

    一.集合 集合是无序的,不重复的数据集合,其元素为可哈希(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键).以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系测试, ...

  10. 介绍一下 NDK?

    1.NDK 是一系列工具的集合 NDK 提供了一系列的工具,帮助开发者快速开发 C(或 C++)的动态库,并能自动将 so 和 java 应用一起打包成 apk.NDK 集成了交叉编译器,并提供了相应 ...