是否可以在编译时看到ARC生成的代码?

时间:2012-05-03 10:49:29

标签: objective-c xcode automatic-ref-counting

我已阅读“摘要”部分中的Transitioning to ARC Release Notes。他们告诉我们:

  

ARC通过在编译时添加代码来确保对象生效   只要有必要,但不再。从概念上讲,它遵循相同的原则   内存管理约定作为手动引用计数(描述   在高级内存管理编程指南)中添加   适当的内存管理需要你。

     

为了让编译器生成正确的代码

我想知道ARC纠正我们代码的结果。

我的问题:我们能看到变化吗? (在分配,保留,分配或释放方面。不是装配级别!)

原因:因为我认为在没有ARC模式的情况下看旧传统开发中的最佳实践代码是件好事。

3 个答案:

答案 0 :(得分:26)

ARC in clang没有通过将代码从ObjC重写到ObjC,但在代码生成期间发出额外的保留/释放LLVM bitcode。这意味着,无法知道编译器如何修复"它没有进入LLVM IR /汇编级别。


  

如果ARC发出LLVM bitcode,就像你说的那样。它的目的是在编译过程中使用更少的时间吗? (不太复杂的ObjC代码,更少的头文件?)

如果编译器可以减少通过代码的次数,那总是更好。


  

您能告诉我一些在汇编级别显示代码的示例或实用程序吗?

要获取汇编代码,您可以

  1. 直接从编译器生成程序集。在命令行中,在调用编译器时添加-S标志。结果是包含汇编代码的.S文件。在Xcode项目中,打开源代码文件,然后转到产品(在菜单栏上)→生成输出程序集文件

  2. 生成目标文件,然后将其反汇编。内置命令otool -tvV <file>可以执行反汇编,还有一些高级工具,如otx(免费)或IDA(免费评估)。

  3. 我更喜欢路由2,因为它产生的垃圾更少,反汇编工具可以配置为产生更多有用的信息。无论如何,使用任何一种方法都需要能够读取汇编代码。

    以此代码为例:

    - (BOOL)application:(UIApplication*)application 
            didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
    {
       self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
       self.window.backgroundColor = [UIColor whiteColor];
       [self.window makeKeyAndVisible];
       return YES;
    }
    

    编译后,将生成以下程序集(使用IDA进行分析):

    -[SomeAppDelegate application:didFinishLaunchingWithOptions:]:
        push       {r4-r7,lr}
        add        r7, sp, #0xC
        str.w      r8, [sp,-#0x4]!
        sub        sp, sp, #0x18
        movw       r1, #(0x343c - 0x2574)       ; @selector(alloc)
        mov        r8, r0
        movt.w     r1, #0
        mov        r0, (0x3464 - 0x2576)        ; _OBJC_CLASS_$_UIWindow
        add        r1, pc
        add        r0, pc
        ldr        r1, [r1]
        ldr        r0, [r0]
        blx        _objc_msgSend
        mov        r1, (0x3440 - 0x258e)        ; @selector(mainScreen)
        mov        r6, r0
        movw       r0, #(0x3468 - 0x2594)       ; _OBJC_CLASS_$_UIScreen
        add        r1, pc
        movt.w     r0, #0
        add        r0, pc
        ldr        r1, [r1]
        ldr        r0, [r0]
        blx        _objc_msgSend
        mov        r7, r7
        blx        _objc_retainAutoreleasedReturnValue
        mov        r5, r0
        cbz        r5, L25ba
        movw       r0, #(0x3444 - 0x25b2)       ; @selector(bounds)
        mov        r1, r5
        movt.w     r0, #0
        add        r0, pc
        ldr        r2, [r0]
        add        r0, sp, #0x8
        blx        _objc_msgSend_stret
        b          L25c4
    
    L25ba:
        add        r0, sp, #0x8
        vmov.i32   q8, #0x80
        vstmia     r0, {d16-d17}
    
    L25c4:
        mov        r1, (0x3448 - 0x25d2)        ; @selector(initWithFrame:)
        ldr        r0, [sp,#0x10]
        add        r1, pc
        ldr        r2, [sp,#0x8]
        ldr        r3, [sp,#0xc]
        ldr        r4, [sp,#0x14]
        stmea.w    sp, {r0,r4}
        mov        r0, r6
        ldr        r1, [r1]
        blx        _objc_msgSend
        mov        r4, r0
        mov        r0, (0x344c - 0x25F2)        ; @selector(setWindow:)
        mov        r2, r4
        add        r0, pc
        ldr        r1, [r0]
        mov        r0, r8
        blx        _objc_msgSend
        mov        r0, r4
        blx        _objc_release
        mov        r0, r5
        blx        _objc_release
        mov        r0, (0x3450 - 0x2610)        ; @selector(window)
        add        r0, pc
        ldr        r5, [r0]
        mov        r0, r8
        mov        r1, r5
        blx        _objc_msgSend
        mov        r7, r7
        blx        _objc_retainAutoreleasedReturnValue
        mov        r1, (0x3454 - 0x2630)        ; @selector(whiteColor)
        mov        r6, r0
        movw       r0, #(0x346C - 0x2636)       ; _OBJC_CLASS_$_UIColor
        add        r1, pc
        movt.w     r0, #0
        add        r0, pc
        ldr        r1, [r1]
        ldr        r0, [r0]
        blx        _objc_msgSend
        mov        r7, r7
        blx        _objc_retainAutoreleasedReturnValue
        mov        r4, r0
        mov        r0, (0x3458 - 0x2652)        ; @selector(setBackgroundColor:)
        mov        r2, r4
        add        r0, pc
        ldr        r1, [r0]
        mov        r0, r6
        blx        _objc_msgSend
        mov        r0, r4
        blx        _objc_release
        mov        r0, r6
        blx        _objc_release
        mov        r0, r8
        mov        r1, r5
        blx        _objc_msgSend
        mov        r7, r7
        blx        _objc_retainAutoreleasedReturnValue
        mov        r4, r0
        mov        r0, (0x345C - 0x2680)        ; @selector(makeKeyAndVisible)
        add        r0, pc
        ldr        r1, [r0]
        mov        r0, r4
        blx        _objc_msgSend
        mov        r0, r4
        blx        _objc_release
        movs       r0, #1
        add        sp, sp, #0x18
        ldr.w      r8, [sp], #4
        pop        {r4-r7,pc}
    

    如果不详细说明,您可以看到有很多_objc_release_objc_retainAutoreleasedReturnValue这些是ARC在代码生成过程中插入的内容。手动反编译,我们会得到:

    UIScreen* r5 = objc_retainAutoreleasedReturnValue([UIScreen mainScreen]);
    CGRect sp8 = r5 != nil ? [r5 bounds] : CGRectZero;
    UIWindow* r4 = [[UIWindow alloc] initWithFrame:sp8];
    [self setWindow:r4];
    objc_release(r4);
    objc_release(r5);
    
    UIWindow* r6a = objc_retainAutoreleasedReturnValue([self window])
    UIColor* r4a = objc_retainAutoreleasedReturnValue([UIColor whiteColor])
    [r6a setBackgroundColor:r4a];
    objc_release(r4a);
    objc_release(r6a);
    
    UIWindow* r4b = objc_retainAutoreleasedReturnValue([self window])
    [r4b makeKeyAndVisible];
    objc_release(r4b);
    
    return 1;
    

    @c roald链接所描述的内容相同。

答案 1 :(得分:2)

Mike Ash在这里对ARC的实施进行了非常有启发性的讨论:http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

他在插入C函数调用(objc_retain(),objc_release(),objc_retainAutoreleaseReturnValue()以及其他一些函数的层面上讨论它,如果这对你有帮助的话。编写这样,编译器可以使用tail-调用优化以消除不必要的步骤。

因此,简短的回答是ARC不使用我们在旧版本的Objecive C中使用的相同[retain] / [release]方法,因此看到ARC预处理的代码不一定会指示你自己该怎么做。

ARC在编译器中作为预处理步骤实现并不罕见 - 我相信Objective C的许多功能都是以这种方式实现的。

答案 2 :(得分:0)

如果不进入LLVM的汇编级详细信息,请不要进入此类详细信息。