美文网首页
简单理解AutoreleasePool

简单理解AutoreleasePool

作者: 雨天多久就 | 来源:发表于2020-02-15 22:29 被阅读0次

    面试官比较喜欢问AutoreleasePool相关的题
    一般问法有两种:
    1.AutoreleasePool管理的对象什么时候释放?
    2.AutoreleasePool的原理是什么?
    如果理解AutoreleasePool的原理,上面两个问题可以很轻松答出来

    AutoreleasePool 是什么?如何存Autorelease对象?
    ARC下,我们通过 @autoreleasepool{}来使用。
    编译器编译后改成了如下的情况:

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

    autoreleasePoolPush 和 autoreleasePoolPop 总是成对出现。它们是对AutoreleasePoolPage的简单封装。
    AutoreleasePoolPage是一个C++类。AutoreleasePool由AutoreleasePoolPage对象通过双向指针链接组合而成。每个AutoreleasePoolPage对象会开辟4096字节内存,除了存放指针,其余空间全部用来存储Autorelease对象的地址
    一个AutoreleasePoolPage存储满了之后,会新创建一个AutoreleasePoolPage对象继续存。

    AutoreleasePool如何释放对象?

    当进行objc_autoreleasePoolPush调用的时候,会在AutoreleasePoolPage里添加一个哨兵对象。
    当objc_autoreleasePoolPop调用的时候,会将从现在位置到哨兵位置的所有对象发送release消息。
    所以出来@autoreleasepool{}作用域后,Autorelease对象就会释放。

    关于主线程里的Autorelease对象释放问题

    主线程的Autorelease对象会自动释放。它们是在每一次runloop进行休眠的时候开始释放的。因为主线程在唤醒执行任务和休眠的时候会自动调用autoreleasePoolPush 和 autoreleasePoolPop。因此相当于整个runloop周期里产生的Autorelease对象都放在了一个自动释放池里。
    下面是测试代码:
    注:在arc情况下,通过__autorelease 标识可以将一个对象标识为Autorelease对象。

    image.png
    • viewWillAppearviewDidload执行在一个runloop周期内,因此viewWillAppear方法执行的时候,mushao这个对象还存在

    • viewDidAppear方法执行的时候,上个runloop周期已经结束了,所以此时mushao那个对象已经释放了

    其实关于AutoReleasePool还有一个面试题,如下:

    Question: touchesBegan方法触发后,能输出error吗?

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        NSError * error = nil;
        [self testArrayISHasCString:&error];
        NSLog(@"error:%@",error);
    }
    
    - (void)testArrayISHasCString:(NSError **)error {
        NSArray * testArray = @[@"a",@"b",@"c",@"d"];
        [testArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj isEqualToString:@"c"]) {
                *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:nil];
            }
        }];
    }
    

    答案是会crash。
    因为enumerateObjectsUsingBlock会在block内部添加AutoreleasePool,所以error对象刚刚生成后,出来作用域就会释放掉。因此外界访问一个释放掉的对象,就会crash掉

    相关文章

      网友评论

          本文标题:简单理解AutoreleasePool

          本文链接:https://www.haomeiwen.com/subject/odxufhtx.html