内存管理autorelease

自动释放是在什么时候释放的
在MRC环境下,释放对象有两种方式一种是创建完对象调用autorelease,或者是手动release。为了方便使用对象,一般情况下都是调用autorelease。
要想查看到调用了autorelease的对象什么时候会被释放,就要先研究一下,autoreleasepool,表面上看是在autoreleasepool的大括号结束的时候,就释放了对象。将代码转成CPP文件查看autoreleasepool的结构,

@autoreleasepool
    {
        Person *person = [[Person alloc] init];//正常情况出了大括号就会自动销毁
    }
//转成cpp
{ __AtAutoreleasePool __autoreleasepool;
 //相当于在这里调用了构造函数
 atautoreleasepoolobj = objc_autoreleasePoolPush();
     Person *person = [[Person alloc] init];
 //在大括号结束的时候调用了析构函数
 objc_autoreleasePoolPop(atautoreleasepoolobj);
 }
 
 struct __AtAutoreleasePool {
   __AtAutoreleasePool() {//构造函数,在结构体创建的时候调用
 atautoreleasepoolobj = objc_autoreleasePoolPush();}
   ~__AtAutoreleasePool() {//析构函数,在结构体销毁的时候调用
 objc_autoreleasePoolPop(atautoreleasepoolobj);}
   void * atautoreleasepoolobj;
 };

以此类推,没增加一个autoreleasepool就会多增加一次上面的结构

02 objc_autoreleasePoolPush和objc_autoreleasePoolPop做的事情

要清楚autorelease对象什么时候销毁,就要高清这两个函数做了什么事情
通过源码可以看出他们通过方法调用来操作autoreleasepoolPage
自动释放池的主要底层数据结构是:__AtAutoreleasePool、AutoreleasePoolPage
调用了autorelease的对象,他的生命周期最终都是通过AutoreleasePoolPage对象来管理的
源码分析
clang重写@autoreleasepool
objc4源码:NSObject.mm

autoreleasepoolPage

每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址
所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起
双向链表就是两个对象产生联系,左边的对象有个指针指向右边的对象,右边的对象也有个指针指向左边的对象,
因为内存是有限的,一个autoreleasepoolpage只有4096当不够的时候就会使用新的page
AutoreleasePoolPage里面一个begin和end一点调用begin他就会返回存放autorelease对象的首个地址,其实就是用this指针+sizeof(this)

page的双向链表

03push和pop做的事情

调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址,然后将autorelease对象放在这个地址后面,如果这个autoreleasepoolPage空间放满了,那么会创建一个新的page来存放autorelease对象,
调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
id *next指向了下一个能存放autorelease对象地址的区域,
当出现多个autoreleasepool嵌套的时候,没出现一个push都会加入一个POOL_BOUNDARY

04

poolPage的结构,
如果是有多个autoreleasepool对象,如果page的内存够,他们会放到同一个page中,这一个page满了之后才会往下面存

objc[1228]: ##############
objc[1228]: AUTORELEASE POOLS for thread 0x1000d2dc0
objc[1228]: 7 releases pending.
objc[1228]: [0x101803000]  ................  PAGE  (hot) (cold)
objc[1228]: [0x101803038]  ################  POOL 0x101803038
objc[1228]: [0x101803040]       0x10051b200  Person
objc[1228]: [0x101803048]       0x100519700  Person
objc[1228]: [0x101803050]  ################  POOL 0x101803050
objc[1228]: [0x101803058]       0x100519290  Person
objc[1228]: [0x101803060]       0x1005188c0  Person
objc[1228]: [0x101803068]       0x100516cf0  NSObject
objc[1228]: ##############

cold和hot
hot是指当前正在使用的page,如果我们取对象是从当前page中开始,那么当前的page就可以称作hot

05push和pop的具体调用过程

autorelease和runloop01

autorelease对象会在什么时机调用release
如果这个对象是被一个autoreleasepool包裹住的话,他的release时机就在这个大括号的结束
如果没有的话,

autorelease和runloop02

runloop其实在主线程中注册了两个observer的
第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
第2个Observer
监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

这个对象什么时候释放是有runloop控制的
他可能是在某次循环中,runloop休眠之前调用了release

方法中有局部对象,出了括号就马上释放么?
如果这个对象是通过autorelease的方式的话,不是马上释放,要等那次runloop休眠之前释放,如果是普通的arc代码是会马上释放的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值