iOS底层原理 - 内存管理 之 RunLoop和autorelease

面试题引发的思考:

Q: autorelease对象在什么时机会被调用release

  • 调用时机是由 RunLoop 来控制的;
  • 在某次 RunLoop循环 中,RunLoop休眠之前 调用了release

Q: ARC方法里有局部对象,出了方法后会立即释放吗?

  • ARC生成的代码是在 方法完成之前 给 对象调用了一次release
  • 对象会在 方法结束之后 立即释放。

1. autorelease对象在什么时机会被调用release

(0) 在MRC环境下:

// TODO: -----------------  Person类  -----------------
@interface Person : NSObject
@end

@implementation Person
- (void)dealloc {
    NSLog(@"%s", __func__);
    [super dealloc];
}
@end

(1) 案例一

// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];    

    NSLog(@"begin");
    @autoreleasepool {
        Person *person = [[[Person alloc] init] autorelease];
    }
    NSLog(@"end");
}

// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] end

由打印结果可知:

autoreleasepool中调用autorelease方法的person对象会在autoreleasepool{}结束后释放。


(2) 案例二

// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];    

    NSLog(@"begin");
    Person *person = [[[Person alloc] init] autorelease];
    NSLog(@"end");
}

// 打印结果
Demo[1234:567890] begin
Demo[1234:567890] end
Demo[1234:567890] -[Person dealloc]

由打印结果可知:

viewDidLoad中调用autorelease方法的person对象会在viewDidLoad结束后释放。


(3) Q: 那么具体释放时机是什么呢?

1> 猜想一:main函数的autoreleasepool
main函数

程序的main函数中虽然有一个autoreleasepool,但是在程序退出之前autoreleasepool是不会结束的;

而在viewDidLoad中调用autorelease方法的person对象会在viewDidLoad结束后释放,所以肯定不是被main函数的autoreleasepool管理的

2> 猜想二:viewDidLoad方法调用完毕释放
// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];    
    Person *person = [[[Person alloc] init] autorelease];
    NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"%s", __func__);
}

// 打印结果
Demo[1234:567890] -[ViewController viewDidLoad]
Demo[1234:567890] -[ViewController viewWillAppear:]
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] -[ViewController viewDidAppear:]

由打印结果可知:

viewDidLoad中初始化的person对象会在viewDidLoadviewWillAppear:执行完毕之后,才会调用person对象的release方法。

Q:不在viewDidLoad中初始化的autorelease对象会在什么时机会被调用release呢?


2. RunLoop和autorelease

打印主线程的RunLoop:

// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];
    // 打印主线程的RunLoop
    NSLog(@"%@", [NSRunLoop mainRunLoop]);
}
observers
Run Loop Observer Activities
  • iOS在主线程的Runloop中注册了2个Observer
  • 第一个Observeractivities = 0x1
    activities = 1表示kCFRunLoopEntry
  • 第二个Observeractivities = 0xa0
    activities =160 = 32 + 128表示kCFRunLoopBeforeWaiting | kCFRunLoopExit

iOS底层原理 - 探寻RunLoop本质(一)可知RunLoop内部实现逻辑:

RunLoop内部实现逻辑

由以上分析可知:

iOS在主线程的Runloop中注册了2个Observer

  • 第1个Observer
    监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
  • 第2个Observer
    监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()objc_autoreleasePoolPush()
    监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

回顾以上的案例:

// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];    
    // 这个Person什么时候调用release,是由RunLoop来控制的
    // 它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release
    Person *person = [[[Person alloc] init] autorelease];
    NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"%s", __func__);
}

// 打印结果
Demo[1234:567890] -[ViewController viewDidLoad]
Demo[1234:567890] -[ViewController viewWillAppear:]
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] -[ViewController viewDidAppear:]

因为person对象会在RunLoop休眠之前被释放,那么可知:

viewDidLoadviewWillAppear处在同一次运行循环中。


3. ARC局部对象释放时机

既然autorelease对象什么时候调用release,是由RunLoop来控制的;

Q: 那ARC方法里的局部对象也是编译器自动在对象后追加autorelease,在RunLoop休眠之前调用了release吗?

ARC环境下执行以下代码:

// TODO: -----------------  ViewController类  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];    
    Person *person = [[Person alloc] init];
    NSLog(@"%s", __func__);

    // ARC环境下,相当于在方法最后release对象
    //[person release];
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"%s", __func__);
}

// 打印结果
Demo[1234:567890] -[ViewController viewDidLoad]
Demo[1234:567890] -[Person dealloc]
Demo[1234:567890] -[ViewController viewWillAppear:]
Demo[1234:567890] -[ViewController viewDidAppear:]

由打印结果可知:

viewDidLoad执行完后person对象立即就被释放了,说明:

ARC生成的代码是在方法完成之前给对象调用了一次release,对象会在方法结束之后立即释放。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容