美文网首页对移动开发有帮助ARC 小知识系列
ARC 环境下,下面代码中的局部变量是何时被销毁的?

ARC 环境下,下面代码中的局部变量是何时被销毁的?

作者: 酷酷的哀殿 | 来源:发表于2016-09-04 11:54 被阅读781次
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSArray *arr = [NSArray arrayWithObject:@"sun"];
    }
    

    前言

    前天挖了一个坑,今天先把它填上。
    本文适合简单快速的回答面试官的问题。对于更深的相关知识,请关注后续的文章或者自行查阅相关资料。

    简单版答案

    在 ARC 下,+arrayWithObject: 方法会自动调用 -autorelease 方法。
    调用后,该变量会被添加到自动释放池。
    在主线程中,临时变量会在 runloop 运行结束时释放。
    在非主线程中,临时变量会在 线程退出时释放。
    所以,当有大量的临时对象时,官方建议我们使用 @autoreleasepool 进行内存管理。

    NSArray *urls = <# An array of file URLs #>;
    for (NSURL *url in urls) {
     
        @autoreleasepool {
            NSError *error;
            NSString *fileContents = [NSString stringWithContentsOfURL:url
                                             encoding:NSUTF8StringEncoding error:&error];
            /* Process the string, creating and autoreleasing more objects. */
        }
    }
    

    测试

    为了测试,本文创建了一个类,SunObject 并实现了 -dealloc方法。

    测试代码

    @interface SunObject : NSObject
    
    @end
    
    @implementation SunObject
    
    - (void)dealloc {
    }
    
    @end
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        __unused NSMutableArray *arr = [NSMutableArray arrayWithObject:[SunObject new]];
    }
    
    

    Allocations

    通过 Allocations 工具,我们可以查看变量的生命周期。如下图所示。

    Paste_Image.png

    下面是手动打印的调用栈。可以明显发现 释放操作是在 libobjc.A.dylib(anonymous namespace)::AutoreleasePoolPage::pop(void*)`的后面。

    (lldb) bt
    * thread #1: tid = 0x44ecce, 0x0000000105118597 内存管理`-[SunObject dealloc](self=0x00007fbbb0e09650, _cmd="dealloc") + 23 at ViewController.m:22, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
      * frame #0: 0x0000000105118597 内存管理`-[SunObject dealloc](self=0x00007fbbb0e09650, _cmd="dealloc") + 23 at ViewController.m:22
        frame #1: 0x000000010562eafe libobjc.A.dylib`objc_object::sidetable_release(bool) + 232
        frame #2: 0x0000000105a8498d CoreFoundation`-[__NSArrayM dealloc] + 157
        frame #3: 0x000000010562eafe libobjc.A.dylib`objc_object::sidetable_release(bool) + 232
        frame #4: 0x000000010562f0b8 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 488
        frame #5: 0x00000001089c58d0 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 32
        frame #6: 0x00000001089c5741 FrontBoardServices`-[FBSSerialQueue _performNext] + 178
        frame #7: 0x00000001089c5aca FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 45
        frame #8: 0x0000000105acc301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
        frame #9: 0x0000000105ac222c CoreFoundation`__CFRunLoopDoSources0 + 556
        frame #10: 0x0000000105ac16e3 CoreFoundation`__CFRunLoopRun + 867
        frame #11: 0x0000000105ac10f8 CoreFoundation`CFRunLoopRunSpecific + 488
        frame #12: 0x0000000105f57f21 UIKit`-[UIApplication _run] + 402
        frame #13: 0x0000000105f5cf09 UIKit`UIApplicationMain + 171
        frame #14: 0x0000000105118b9f 内存管理`main(argc=1, argv=0x00007fff5aae76a0) + 111 at main.m:14
        frame #15: 0x000000010838092d libdyld.dylib`start + 1
    (lldb) 
    

    相关文章

      网友评论

      • 啊哈呵:发现了奇怪的现象:
        extern void _objc_autoreleasePoolPrint(void); //extern这个方法,输出pool里面的对象
        // 测试1
        @autoreleasepool {
        id obj1 = [NSMutableArray array];
        _objc_autoreleasePoolPrint(); // PoolPrint最后没有obj1对应的对象
        NSLog(@"=====%@",obj1);
        }
        // 测试2
        __weak id obj = nil; // 随便写这么一句代码,__weak修饰,结果与测试1就不同了
        @autoreleasepool {
        id obj2 = [NSMutableArray array];
        _objc_autoreleasePoolPrint(); // PoolPrint看到obj2对应的对象(最后是 __NSArrayM)
        NSLog(@"=====%@",obj2);
        }
        //疑惑:为什么随便写一句weak代码,就导致测试1、2的不同呢?
        酷酷的哀殿:@啊哈呵 你汇编一下
      • 751fc49dcbfd:分线程 未在 线程执行完毕之后dealloc
        经过我测试
      • niuxinghua:runloop event一次迭代结束销毁。。nsarray这个还要考虑跟里面object的关系?
      • 戴仓薯:我猜…… 函数体结束的时候呗~
        戴仓薯:@酷酷的哀殿 刚试了一下,出了函数体再访问跟 arr 同样地址的指针,是 EXC_BAD_ACCESS 呀。我感觉对象销毁应该就是这时候,内存释放的时机是后面不定时间。
        戴仓薯:@酷酷的哀殿 好吧= =
        酷酷的哀殿: @戴仓薯 看样子,这是一个合适的面试题

      本文标题:ARC 环境下,下面代码中的局部变量是何时被销毁的?

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