面试题答案
一键面试MRC(手动引用计数)内存管理方式
在MRC下,开发者需要手动管理对象的内存。每个对象都有一个引用计数(retain count),当对象被创建时,引用计数为1。
- retain:发送
retain
消息会使对象的引用计数加1。例如NSObject *obj = [[NSObject alloc] init]; [obj retain];
,这样obj
的引用计数变为2。 - release:发送
release
消息会使对象的引用计数减1。例如[obj release];
,obj
的引用计数变为1。当引用计数降为0时,对象会被销毁,其占用的内存会被释放。 - autorelease:发送
autorelease
消息会将对象放入自动释放池(autorelease pool)。当自动释放池被销毁时,池中的所有对象都会收到release
消息。例如NSObject *obj = [[[NSObject alloc] init] autorelease];
,对象obj
会在自动释放池销毁时被释放。
ARC(自动引用计数)工作原理
ARC是由编译器自动管理对象的内存。编译器会在适当的位置自动插入retain
、release
和autorelease
代码。
- 对象生命周期管理:当对象被创建时,ARC会为其分配内存并设置引用计数为1。当对象的引用计数变为0时,ARC会自动释放对象所占用的内存。
- 作用域相关:当对象超出其作用域(例如函数结束、局部变量所在块结束),如果没有其他强引用指向该对象,ARC会自动减少其引用计数,可能导致对象被释放。
ARC的优点
- 减少内存管理错误:开发者无需手动编写
retain
、release
代码,大大减少了因忘记释放对象(内存泄漏)或过度释放(野指针)导致的错误。 - 提高开发效率:节省了开发者处理内存管理的时间,使开发者可以更专注于业务逻辑。
- 性能优化:ARC可以根据对象的生命周期更高效地管理内存,减少不必要的引用计数操作。
ARC的潜在问题
- 循环引用:如果两个或多个对象相互强引用,就会形成循环引用,导致对象无法释放。这在ARC下依然存在。
- 调试困难:由于内存管理代码由编译器自动插入,当出现内存相关问题时,调试难度可能会增加,因为开发者看不到直接的内存管理代码。
在ARC环境下处理循环引用问题
- 使用弱引用(weak reference):对于相互引用的情况,将其中一个引用声明为
weak
。例如在一个视图控制器(ViewController)和其内部的一个自定义视图(CustomView)相互引用时,在CustomView
中对ViewController
的引用可以声明为weak
:
@property (nonatomic, weak) ViewController *viewController;
weak
引用不会增加对象的引用计数,从而打破循环引用。
2. 使用无主引用(unowned reference):类似于weak
,但unowned
引用不会被自动设置为nil
,当被引用对象被释放后,unowned
引用会变成野指针。适用于确定被引用对象的生命周期至少和引用对象一样长的情况。例如:
@property (nonatomic, unowned) SomeObject *otherObject;