autorelease什么时候释放_Autorelease返回值的快速释放机制

+ (instancetype)createSark {

return [self new];

}

// caller

Sark *sark = [Sark createSark];

编译器改写成了形如下面的代码:

+ (instancetype)createSark {

id tmp = [self new];

return objc_autoreleaseReturnValue(tmp); // 代替我们调用autorelease

}

// caller

id tmp = objc_retainAutoreleasedReturnValue([Sark createSark]) // 代替我们调用retain

Sark *sark = tmp;

objc_storeStrong(&sark, nil); // 相当于代替我们调用了release

runtime使用了一些黑魔法进行了优化

Thread Local Storage

Thread Local Storage(TLS)线程局部存储,目的很简单,将一块内存作为某个线程专有的存储,以key-value的形式进行读写,比如在非arm架构下,使用pthread提供的方法实现:

void* pthread_getspecific(pthread_key_t);

int pthread_setspecific(pthread_key_t , const void *);

在返回值身上调用objc_autoreleaseReturnValue方法时,runtime将这个返回值object储存在TLS中,然后直接返回这个object(不调用autorelease);同时,在外部接收这个返回值的objc_retainAutoreleasedReturnValue里,发现TLS中正好存了这个对象,那么直接返回这个object(不调用retain)。

于是乎,调用方和被调方利用TLS做中转,很有默契的免去了对返回值的内存管理。

于是问题又来了,

只能动用更高级的黑魔法。

__builtin_return_address

假如被调方和主调方只有一边是ARC环境编译,(比如我们在ARC环境下用了非ARC编译的第三方库,或者反之),需要用到__builtin_return_address

这个内建函数原型是 char *__builtin_return_address(int level),

作用是得到函数的返回地址,参数表示层数,如__builtin_return_address(0)表示当前函数体返回地址,传1是调用这个函数的外层函数的返回值地址,以此类推。

- (int)foo {

NSLog(@"%p", __builtin_return_address(0)); // 根据这个地址能找到下面ret的地址

return 1;

}

// caller

int ret = [sark foo];

函数的返回值地址,也就对应着调用者结束这次调用的地址(或者相差某个固定的偏移量,根据编译器决定)

如果一个函数返回前知道调用方是ARC还是非ARC,就有机会对于不同情况做不同的处理

##黑魔法之反查汇编指令

通过上面的__builtin_return_address加某些偏移量,被调方可以定位到主调方在返回值后面的汇编指令:

于是乎,就有了下面的这个函数,入参是调用方__builtin_return_address传入值

static bool callerAcceptsFastAutorelease(const void * const ra0) {

const uint8_t *ra1 = (const uint8_t *)ra0;

const uint16_t *ra2;

const uint32_t *ra4 = (const uint32_t *)ra1;

const void **sym;

// 48 89 c7 movq %rax,%rdi

// e8 callq symbol

if (*ra4 != 0xe8c78948) {

return false;

}

ra1 += (long)*(const int32_t *)(ra1 + 4) + 8l;

ra2 = (const uint16_t *)ra1;

// ff 25 jmpq *symbol@DYLDMAGIC(%rip)

if (*ra2 != 0x25ff) {

return false;

}

ra1 += 6l + (long)*(const int32_t *)(ra1 + 2);

sym = (const void **)ra1;

if (*sym != objc_retainAutoreleasedReturnValue)

{

return false;

}

return true;

}

它检验了主调方在返回值之后是否紧接着调用了objc_retainAutoreleasedReturnValue,如果是,就知道了外部是ARC环境,反之就走没被优化的老逻辑。

其他Autorelease相关知识点

使用容器的block版本的枚举器时,内部会自动添加一个AutoreleasePool:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

// 这里被一个局部@autoreleasepool包围着

}];

当然,在普通for循环和for in循环中没有,所以,还是新版的block版本枚举器更加方便。for循环中遍历产生大量autorelease变量时,就需要手加局部AutoreleasePool咯。

http协议中各个响应状态200_301_404_500等返回值含义快速一览

一.定义 从HTTP的定义可以看出,HTTP协议是互联网上进行数据通信的基础协议,用来交换或传输超文本.超文本是一种结构化的文本,在包含文本的节点之间使用逻辑链接(也叫超链接). 二.概述 HTTP是 ...

GsonFormat根据返回值json快速构建Model

Json是一个插件,我们只需要在Android studio中进行安装一下,即可使用. 根据平时的操作,根据浏览器中返回中的数据一行一行敲,其实这样非常麻烦. 有一个简单的方法,可以瞬间生成一个实体类 ...

c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别

一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...

Java反射机制二 获取方法的返回值或参数的泛型信息

在使用反射机制时,我们经常需要知道方法的参数和返回值类型,很简单  ,下面上示例,示例中的两个方法非常相似 package deadLockThread; import java.lang.refle ...

idea 快速生成返回值快捷方式

idea java快速生成返回值   ctrl+alt+V

关于java中ArrayList的快速失败机制的漏洞——使用迭代器循环时删除倒数第二个元素不会报错

一.问题描述 话不多说,先上代码: public static void main(String[] args) throws InterruptedException { List

GetLastError()函数返回值及含义

GetLastError返回的值通过在api函数中调用SetLastError或SetLastErrorEx设置.函数并无必要设置上一次错误信息,所以即使一次GetLastError调用返回的是零值, ...

快速失败机制--fail-fast

fail-fast 机制是Java集合(Collection)中的一种错误机制.当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast(快速失败)事件.例如:当某一个线程A通过iter ...

Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数

Python第七天   函数  函数参数   函数里的变量   函数返回值  多类型传值     函数递归调用   匿名函数   内置函数 目录 Pycharm使用技巧(转载) Python第一天   ...

随机推荐

CentOS 7 上编译安装MySQL 5.6.23

1.下载源码 wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.23.tar.gz 2.解压 tar zxvf mysql-5.6 ...

vim命令---存阅

命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filename 打开vim ...

IOS本地化应用

BK项目已完成7788,在项目的后期需要被翻译成多国语言版.为了适应全球多个国家使用多个存储. 应用本地化是分别对字符串.图片和 xib 或 storyboard 文件本地化,而传统的做法是对 xib ...

关于this指针理解

1. this指针的用处: 一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果.this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将 ...

Java程序基础编程基础

1.在屏幕上输出"你好" //Programmer name Helloword.javapublic class Helloword { public static void m ...

QTableWidget class

Help on class QTableWidget in module PyQt5.QtWidgets: class QTableWidget(QTableView)  |  QTableWidge ...

C语言中的语句

• 表达式语句 表达式后加 ; 构成表达式语句. a = b+c; x+y i++ • 控制语句 完成一定的控制功能. if(...){...}else{...}                   ...

MySQL自定义函数和存储过程的区别:

自定义函数和存储过程的区别: 1)一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强.存储过程,功能强大,可以执行包括修改表等一系列数据库操作:用户定义函数不能用于执行一组修改全局 ...

dart --- 更符合程序员编程习惯的javascript替代者

dart是google在2011年推出的一门语言,提供较为丰富的lib,并支持将代码转变为javascript,其demo code 和 demo app 也是以web前端代码来展示的. 其语言特性较 ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值