iOS 基础知识之–autorelease
先来看一个问题
分别在在 MRC 和 ARC 情况下,下面的两段代码,会不会会引起内存的暴涨?
- (void)demo2{
    for (int i = 0; i < 100000000; i++) {
        NSString *yunis = [NSString stringWithFormat:@"Yunis"];
    }
}
- (void)demo3{
    for (int i = 0; i < 100000000; i++) {
        NSString *yunisAlloc = [[NSString alloc] initWithFormat:@"YunisAlloc"];
    }
}

测试环境: Xcode 9.1 iPhone 8 Plus(模拟器) iOS 11.1 
公布答案:
- MRC下:- 
        demo2  
- 
        demo3  
 
- 
        
- ARC下:- 
        demo2  
- 
        demo3  
 
- 
        
在 ARC 下,内存差别是不大的,但是在 MRC 的情况下,demo3 的代码会导致内存疯狂增长。为什么呢?
这里我们猜想:是因为 stringWithFormat 方法返回的对象是有一个 _autorelease 属性修饰的。所以 demo2 中的 yunis,会自动释放,这就是为什么 demo2 在 ARC 和 MRC 下内存都变化不大的原因,而 ` alloc] initWithFormat ` 返回的对象是没有 _autorelease 修饰的,所以他不会自动释放,需要我们手动调用 autorelease ,才能释放。真的是因为这样吗?
初识 autorelease
接着上一个问题,在 MRC 下,我们小小的修改下 demo3 代码,变为:
- (void)demo3{
    for (int i = 0; i < 100000000; i++) {
        NSString *yunisAlloc = [[NSString alloc] initWithFormat:@"YunisAlloc"];
        [yunisAlloc autorelease];
    }
}
再来看下内存的情况:

额,内存依然在疯狂的增长,如果我们把 autorelease 换为 release 呢?
- (void)demo3 {
    for (int i = 0; i < 100000000; i++) {
        NSString *yunisAlloc = [[NSString alloc] initWithFormat:@"YunisAlloc"];
        [yunisAlloc release];
    }
}

这时我们发现,内存回到一个正常的状态。
那么问题来了?为什么 autorelease 没用使内存降下来,而 release 可以呢?
难道跟传说中的自动释放池有关系?
进一步的,我们再次修改下 demo3 代码:
- (void)demo3 {
    
    @autoreleasepool{
        for (int i = 0; i < 100000000; i++) {
            NSString *yunisAlloc = [[NSString alloc] initWithFormat:@"YunisAlloc"];
            [yunisAlloc autorelease];
        }
    }
}

握草!!! 我都加了  autorelease 和 @autoreleasepool了,为什么内存还是没有降下去??
然后我去读了经典书籍:《Objective-C高级编程:iOS与OS X多线程和内存管理》。

我读书回来了。

autorelease 对象什么时候释放?
在 《Objective-C高级编程:iOS与OS X多线程和内存管理》 是这样说的:
NSAutoreleasePool对象的生存周期相当于 C 语言变量的作用域。对于调用autorelease实例方法的对象,在废弃NSAutoreleasePool对象时,都将调用release实例方法。
那么现在来看为什么我们的 demo3 加了 NSAutoreleasePool 和  autorelease 后内存依然没有降低的原因就清晰明了了。修改代码:
- (void)demo3 {
    for (int i = 0; i < 100000000; i++)
    {
        @autoreleasepool {
            NSString *yunisAlloc = [[NSString alloc] initWithFormat:@"YunisAlloc"];
            [yunisAlloc autorelease];
        }
    }
}

内存回到一个正常的状态。
OK ,让我们来理一下思路。
对于 demo2 中的代码,因为返回的是一个使用 _autorelease 修饰的对象,已经自动加入释放池了,所以内存没有显著的增长。
但是对于一个 alloc init 生成的实例变量,在 MRC 下需要用户手动的管理引用计数,同时对于短时间大量生成的局部变量,应及时的释放其内存。对于调用 autorelease 实例方法的实例对象,会在自动释放池 drain 后,才调用实例对象的 release 实例方法。
那么,在 ARC 下,系统对 demo3 为我们做了什么?跟我们自己在 MRC 编写的代码逻辑一致吗?
同时,返回 _autorelease 修饰的实例是加入了那个自动释放池?这个自动释放池的生存周期又是什么样的?它为什么没有造成大量的内存增长?

这个结论对 UIView 好像不成立!!!!!
这个结论对 UIView 好像不成立!!!!!
这个结论对 UIView 好像不成立!!!!!
这个结论对 UIView 好像不成立!!!!!
这个结论对 UIView 好像不成立!!!!!
这个结论对 UIView 好像不成立!!!!!
挖槽 这个问题挖下去 好像 还得看看 runLoop !!!
- 为什么 uiview 在 autoreleasepool 不生效?
- _autorelease 修饰的实例 是存在于那个 autoreleasepool?
我TM好像给自己挖了一个深坑!!!!!!
去 孙源大神的博客研究下:
https://blog.sunnyxx.com/2014/10/15/behind-autorelease/
