美文网首页
ARC下AutoReleasePool的误区

ARC下AutoReleasePool的误区

作者: Yasin的简书 | 来源:发表于2022-05-12 20:42 被阅读0次

    写这边文章的原因是看到网络上对于AutoReleasePool讨论,发现大家对AutoReleasePool存在误区。

    AutoReleasePool 里面的对象何时释放?

    这个问题是常见的iOS面试题,错误的答案:
    1.等到一次runloop结束,AutoReleasePool被释放时
    2.超出作用域{}

    这些答案都不对,标准答案:
    每次release时retainCount减一,当retainCount为0时候释放对象。release的时机比如runloop周期中AutoReleasePool被释放时,比如超出作用域时

    关键概念点:
    1. 不是所有OC对象都会加入到AutoReleasePool
    2. AutoReleasePool被释放时里面的对象不一定会释放,超出作用域一样不一定会释放

    1. 不是所有OC对象都会加入到AutoReleasePool
      AutoReleasePool是ARC的一部分,本质上还是RC的机制,一个对象在ARC下,可能会被加入到autoreleasepool里面,也可能不会。比如被__autoreleasing标记或者@autoreleasepool包裹的或者UIImage对象都会加入AutoReleasePool,其他的像只是单纯创建NSObject是不会,但是调用了NSObject的对象方法后是会加入AutoReleasePool的。
    1. AutoReleasePool被释放时里面的对象不一定会释放,超出作用域同样的道理
      AutoReleasePool被释放时里面的对象可能还有其他引用,所以AutoReleasePool被释放时里面的对象只会执行release操作,并不一定会释放对象。
    正常情况:
        __weak id objA = nil;
        {
            id objB = [NSObject new];
            objA = objB;
        }
        NSLog(@"%@", objA);
        // objA = null
    

    这个是没有异议的情况,objB出了作用域就会被释放,但是下面的代码就不一样了

    AutoReleasePool被释放时有其他引用:
        id objA = nil;
        @autoreleasepool {
            id objB = [NSObject new];
            objA = objB;
        }
        NSLog(@"%@", objA);
        // objA = <NSObject: 0x600002708330>
    

    objB虽然被加入到自动释放池,但是并不会被释放掉,因为还有objA在强引用它。如果这里的objA是weak的,objB会被释放

    出了作用域但是AutoReleasePool没有释放:
        __weak id objA = nil;
        {
            __autoreleasing id objB = [NSObject new];
            objA = objB;
        }
        NSLog(@"%@", objA);
        // objA = <NSObject: 0x600000c545c0>
    

    objA虽然是弱引用,但是__autoreleasing的AutoReleasePool是和objA同级的,要等AutoReleasePool释放的时候objB才会被释放,即使objB已经出了作用域,其实这里出作用域的时候并没有执行release操作

    AutoReleasePool释放了,同时出了作用域,就会被释放:
        __weak id objA = nil;
        {
            id objB = nil;
            @autoreleasepool {
                __autoreleasing NSObject *objC = [NSObject new];
                objB = objC;
            }
            objA = objB;
            NSLog(@"objA = %@", objA);
            //objA = <NSObject: 0x60000188c0c0>
        }
        NSLog(@"objA = %@", objA);
        //objA = null
    

    源码分析

    autoreleasepool pop源码:


    image.png

    release中的源码:


    image.png

    总结:

    1. 并不是所有对象都会被自动加入到AutoReleasePool
    2. runloop周期结束的时候AutoReleasePool会被释放
    3. AutoReleasePool被释放时里面的对象会执行release操作,但是并不一定会释放
    4. AutoReleasePool里面的对象要等到retainCount为0时候释放
    5. AutoReleasePool里面的对象出作用域的时候并不会立即执行release操作
    6. for循环中的对象如果造成了内存暴增,可以用@autoreleasepool 加入到临时自动释放池

    相关文章

      网友评论

          本文标题:ARC下AutoReleasePool的误区

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