代码改变世界

iOS进阶四-自动释放池原理

2019-05-19 13:29  iCoderHong  阅读(2900)  评论(1编辑  收藏  举报

概述

AutoreleasePool(自动释放池)是OC中的一种内存自动回收机制,它可以延迟加入AutoreleasePool中的变量release的时机。在正常情况下,创建的变量会在超出其作用域的时候release,但是如果将变量加入AutoreleasePool,那么release将延迟执行。

@autoreleasepool实现本质

在终端中使用clang -rewrite-objc命令将OC代码重写成C++的实现

 

 __AtAutoreleasePool是C++定义类

 

 @autoreleasepool最终实现如下

 AutoreleasePoolPage

自动释放池的主要底层数据结构是:__AtAutoreleasePool 和 AutoreleasePoolPage

调用了autorelease的对象最终由AutoreleasePoolPage对象来管理

 objc4源码:NSObject.mm

 

每一个AutoreleasePoolPage对象占用4094字节内存,本身成员占用56字节,剩下的空间用来存放autorelease对象的地址

所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起

 

AutoreleasePoolPage管理autorelease的的对象过程 

@autoreleasepool {}就对应 objc_autoreleasePoolPush(); 和  objc_autoreleasePoolPop(atautoreleasepoolobj);

objc_autoreleasePoolPush(); 内部实现:往当前hot AutoreleasePoolPage 添加 POOL_BOUNDARY,返回POOL_BOUNDARY所在的内存地址

@autoreleasepool {}代码快如果存在对象调用了autorelease,就会将对象内存地址保存至AutoreleasePoolPage 

objc4 NSObject.mm 对象- (id)autorelease方法实现

 

添加POOL_BOUNDARY和AutoreleasePoolPage对象后如下图 

每执行@autoreleasepool底层对应执行objc_autoreleasePoolPush(); 就会往AutoreleasePoolPage添加POOL_BOUNDARY,并返回POOL_BOUNDARY所在AutoreleasePoolPage的内存空间地址

@autoreleasepool{}大括号结束 内部创建的__AtAutoreleasePool对象销毁,调用析构函数objc_autoreleasePoolPop(atautoreleasepoolobj);

AutoreleasePoolPage开始从后往前遍历autorelease对象调用release方法直到objc_autoreleasePoolPop()传入的POOL_BOUNDARY地址为止

 查看AutoreleasePoolPage结构

Foundation内部存在一个全局的函数 声明引用 然后在调用

控制台输出

 

 RunLoop与autorelease

iOS程序运行 在主线程中注册了2个Observer 分别监听RunLoop的 kCFRunLoopEntry  kCFRunLoopBeforeWaiting 两个状态(通过打印主线程的RunLoop)

第一个Observer监听了kCFRunLoopEntry 会调用objc_autoreleasePoolPush

第二个Observer监听了kCFRunLoopBeforeWaiting 会调用objc_autoreleasePoolPop

 MRC环境 调用的autorelease对象销毁时机

iOS程序在程序入口main函数执行@autoreleasepool也就是atautoreleasepoolobj = objc_autoreleasePoolPush();操作  保证在程序中对象可以直接调用autorelease 

上图中person对象是有RunLoop来控制的,它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release 

ARC环境 方法中创建局部对象销毁时机 

上图中person对象取决于ARC是对person添加释放代码是生成autorelease还是在方法结束之前生成release,经过调试验证ARC在方法结束前插入一句

[person release],所以ARC下局部对象是在方法结束释放