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

15

我已经阅读了“Transitioning to ARC Release Notes”中的“概述”部分。其中提到:

ARC通过在编译时添加代码来确保对象在必要时间内存活,但不会过度存活。从概念上讲,它遵循手动引用计数(在《高级内存管理编程指南》中有描述)的内存管理规约,为您添加适当的内存管理调用。

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

我想知道 ARC 如何修正我们的代码。

我的问题:我们能看到这些变化吗?(以 alloc、retain、assign 或 release 的术语表示,而非汇编级别!)

原因:因为我认为在旧的传统开发模式下查看最佳实践代码是有益的,而不使用 ARC 模式。


1
对于这个案例研究,我所指的“旧传统开发”是关于如何正确地分配、保留、分配或释放它们。我也不想在汇编细节上硬编码 :-)。 - Sakares
你可以直接阅读引用文章中链接的文档,ARC只是执行了该文章中描述的相同操作。请先阅读“内存管理策略”部分,大多数日常编程中使用的ARC规则都源自于此。https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html - Dietrich Epp
可能是Seeing where ARC is inserting retain and releases的重复问题。 - jscs
3个回答

27

在clang中,ARC不是通过将ObjC代码重写为ObjC来实现的,而是在代码生成过程中发出了额外的retain/release LLVM位码。这意味着,如果不到达LLVM IR /汇编级别,就无法知道编译器如何"修复"它。


如果像你说的那样,ARC会发出LLVM位码。这是否是为了在编译过程中使用更少的时间?(更简单的ObjC代码,更少的头文件?)

如果编译器可以减少对代码的遍历次数,那肯定是更好的。


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

要获取汇编代码,您可以:

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

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

我更喜欢第二种方法,因为它生成的垃圾较少,反汇编工具可以配置为产生更有用的信息。无论哪种方法,您都需要能够阅读汇编代码。

以此代码为例:

- (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;
}

不详细解释,你可以看到有很多_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的链接描述的完全相同。


看起来就像您所说的那样。您觉得在汇编级别发射LLVM位代码,进行快速编译怎么样? - Sakares
@Jojas:抱歉,我不明白你所说的“快速编译”是什么意思。 - kennytm
我想请问您的意见,如果ARC像您所说的那样发出LLVM位码。这是为了在编译过程中使用更少的时间而设计的吗?(较简单的ObjC代码,较少的头文件?) - Sakares
在赏金结束之前,我已经考虑了您的答案,其中包含更详细的知识。您能否向我展示一些示例或实用程序,以显示汇编级别的代码?我认为这可能值得您的奖励。 - Sakares
非常清晰易懂的回答。虽然这不完全是我寻找的答案,但我真的认识到你的回答是了解ARC机制的唯一途径。当然,这是你的奖励!感谢你提供高质量的答案! - Sakares
@kennytm 你是手动按照这些指令来确定哪些值在哪些寄存器中吗? - pash3r

3

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

他讨论了插入C函数调用的层次(objc_retain(),objc_release(),objc_retainAutoreleaseReturnValue()等),如果这对您有帮助。以这种方式编写,编译器可以使用尾调用优化来消除不必要的步骤。

因此,简短的答案是,ARC不使用我们在旧版Objective C中使用的相同的[retain]/[release]方法,因此查看ARC预处理代码不一定会指导您如何自己做。

在编译器中作为预处理步骤实现ARC并不罕见--我认为Objective C的许多特性都是这样实现的。


0

不,你不能在不涉及LLVM汇编级别细节的情况下深入到这样的细节中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接