参考资料:
黑幕背后的Autorelease

autorelease对象什么时候释放

在没有手动添加@autoreleasepool{}的情况下,autorelease对象会在当前runloop迭代结束的时候释放,而他能够释放的原因是系统在每个ruploop迭代中都加入了自动释池的Push和Pop操作。

autorelease的原理

autorelease是和线程一一对应的,一个线程里面只有一个autorelease,一个autoreleasePool开始的时候会执行void *context = objc_autoreleasePoolPush();代码。autorelease是由多个autoreleasePoolPage通过双向链表的形式组成的。autoreleasePoolPage用栈的形式存储了需要管理的对象。当一个runloop循环结束的时候,会调用objc_autoreleasePoolPop(context)方法通知autorelasePool释放autorelasePoolPage中的对象。

手动写的@autorelasepool { ... } 大括号中的对象会在大括号结束的时候释放。此时编译器会将代码转换为下面的形式:

void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);

即不需要等当前的runloop循环结束就立即执行了Pop操作,释放掉了{}中的对象。这就需要autoreleasePoolPage用来存储对象栈的时候对手动添加的autorelasepool开始新增对象时进行标记。

Autorelease的工作原理

常用的便利构造器方法,实际上就是将生成的对象添加到了自动释放池中。

@interface A : NSObject

+ (instancetype)object;

@end

@implementation A

+ (instancetype)object {
    A *a = [A alloc];
    [a autorelease]; // autorelease自动释放内存 会在一个RunLoop结束的时候释放

    /*
        调用autorelease的实例,会在超出其作用域时执行其release方法。
        autorelease的具体使用方法如下:
        // 1.生成并持有NSAutoreleasePool对象
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        id object0 = [[NSObject alloc] init];
        // 2.调用分配对象的autorelease方法
        [object0 autorelease];
        // 3.废弃NSAutoreleasePool对象 在废弃的同时,系统会调用object的release方法
        [pool drain];

        // 在Cocoa框架中,相当于程序主循环的NSRunLoop或者其他程序可运行的地方,对NSAutoreleasePool对象进行生成、持有和废弃处理。
        // 因此,绝大部分时候,开发者不需要自己写NSAutoreleasePool的相关代码。
        // autorelease实例方法的本质就是调用NSAutoreleasePool对象的addObjec类方法
        // autorelease的内部实现
        - (instancetype)autorelease {
           [NSAutoreleasePool addObject:self];
        }
        // NSAutoreleasePool的类方法 + (void)addObject:(NSObject *)obj 的内部实现:
        + (void)addObject:(NSObject *)obj {
           NSAutoreleasePool *currentAutoreleasePool = [获取当前的NSAutoreleasePool对象];
           [currentAutoreleasePool addObject: obj]; // 调用NSAutoreleasePool对象的实例方法
        }
        // NSAutoreleasePool的实例方法 - (void)addObject:(NSObject *)obj 的内部实现:
        - (void)addObject:(NSObject *)obj {
           [mArray addObject:obj]; // 用一个可变数组存储obj
        }
        // drain的内部实现:
        - (void)drain {
           [self release];
           [mArray release];
        }
        - (void)dealloc {
           for (obj in mArray) {
               [obj release];
           }
        }
     */

    /*
     不能调用NSAutoreleasePool对象的autorelease方法
     在Foundation框架中,无论调用哪个对象的autorelease方法,都是调用NSObject类的autorelease方法;
     但对于NSAutoreleasePool类,autorelease实例方法已经被该类重载,因此运行时会出错。
     */

    return a;
}

@end
Copyright © shuoliu.com 2018 all right reserved,powered by Gitbook该文件修订时间: 2018-09-03 03:46:41

results matching ""

    No results matching ""