iOS_2022_autoreleasePool

AutoreleasePool

 

为何线程的入口要加Autorelease Pool

Linux 多线程环境下 线程joinable状态和unjoinable状态

 

AutoReleasePool是oc的一种自动内存回收机制,可以将一些临时变量通过自动释放池来回收统一释放

在没有手加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop

自动释放池本事销毁的时候,池子里面所有的对象都会做一次release操作

 
用法

对象执行autorelease方法时会将对象添加到自动释放池中

当自动释放池销毁时自动释放池中所有对象作release操作

对象执行autorelease方法后自身引用计数器不会改变,而且会返回对象本身



优点

autorelease实际上只是把对release的调用延迟了,对于每一次autorelease系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release

因为只有在自动释放池销毁的时候它里面的对象才销毁,因此不用关心对象销毁的时间也就不用关心什么时候调用release

 

Autorelease的创建和释放

自动释放池是由objc_autoreleasepoolPush、objc_autoreleasepoolPop和objc_autorelease组成

创建过程分析:

APP启动后,主线程runloop注册了两个observer

第一个observer:即将进入loop事件的回调内会调用objc_autoreleasepoolPush()创建释放池

第二个observer:监视两个事件

  1、准备进入休眠时调用objc_autoreleasepoolPop()和objc_autoreleasepoolPush()释放旧池和创建新池

  2、准备退出runloop时调用objc_autoreleasepoolPop()释放池

 

AutoreleasePool是在RunLoop即将进入RunLoop准备进入休眠这两种状态的时候被创建和销毁的。autoreleasepool 是与线程紧密相关的,每一个 autoreleasepool 只对应一个线程。

在没有手动添加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop。

 

什么时候需要自己手动创建autorelease pool

你写的循环创建了大量临时对象 -> 你需要在循环体内创建一个autorelease pool block并且在每次循环结束之前处理那些autoreleased对象. 在循环中使用autorelease pool block可以降低内存峰值。

 

我们经常会在一些第三方库中看到这种情况,线程的入口加上Autorelease Pool,这是为何?

一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。

在默认情况下线程是joinable,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。

由此可知,线程占用的资源要释放的前提是线程终止,如果加了autoreleasepool相关对象会在pool执行完毕后释放,避免过多的延迟释放造成程序占用过多的内存。

 

 
AutoreleasePool并没有单独的结构。而是由若干个AutoreleasePoolPage以双向链表的形式组合而成(分别相应结构中的parent指针和child指针)。
AutoreleasePool是按线程一一相应的(结构中的thread指针指向当前线程)。

AutoreleasePoolPage每一个对象会开辟4096字节内存(也就是虚拟内存一页的大小)。除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址。

 

上面的id *next指针作为游标指向栈顶最新add进来的autorelease对象的下一个位置。
一个AutoreleasePoolPage的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表,后来的autorelease对象在新的page增加。
所以,若当前线程中仅仅有一个AutoreleasePoolPage对象,并记录了非常多autorelease对象地址时。内存例如以下图:

 

 上图中的情况。这一页再增加一个autorelease对象就要满了(也就是next指针立即指向栈顶),这时就要运行上面说的操作,建立下一页page对象,与这一页链表连接完毕后,新page的next指针被初始化在栈底(begin的位置),然后继续向栈顶增加新对象。

 

释放时刻

 
 
posted @ 2022-08-02 20:34  素染年华  阅读(36)  评论(0编辑  收藏  举报