面试题答案
一键面试ARC跟踪对象引用计数变化及释放机制
- 运行时跟踪原理:
- 在ARC(自动引用计数)机制下,编译器会在编译期自动在代码中合适的位置插入内存管理相关的代码,主要是引用计数的增减操作。
- 运行时系统通过一个引用计数表来跟踪对象的引用计数。每个对象都有一个与之关联的引用计数,这个引用计数记录了当前有多少个变量或表达式引用了该对象。当对象被创建时,引用计数初始化为1。
- 当引用计数变为0时,运行时系统会自动调用对象的
dealloc
方法来释放对象所占用的内存空间。这一过程对开发者是透明的,开发者无需手动调用release
、retain
等方法。
- 不同场景下引用计数的增减操作:
- 赋值场景:
- 强引用赋值:当使用强引用(
__strong
,默认修饰符)进行赋值时,例如id __strong obj1 = [[SomeClass alloc] init]; id __strong obj2 = obj1;
,obj2
会使对象的引用计数增加1。因为obj2
也开始引用该对象。当obj1
被重新赋值或者超出作用域时,对象的引用计数会减1,但只要obj2
还在作用域内且引用该对象,对象就不会被释放。如果obj2
也超出作用域,对象引用计数减为0,对象会被释放。 - 弱引用赋值:使用弱引用(
__weak
)进行赋值,例如id __weak weakObj = strongObj;
,不会增加对象的引用计数。弱引用的目的是为了避免循环引用,并且当对象的引用计数变为0被释放时,指向该对象的所有弱引用会自动被设置为nil
,防止野指针的产生。
- 强引用赋值:当使用强引用(
- 方法调用场景:
- 方法参数传递:当对象作为参数传递给方法时,如果方法内部使用强引用持有该对象,例如
- (void)someMethod:(id __strong)param
,对象的引用计数会增加1。方法执行完毕,局部变量param
超出作用域,引用计数减1。如果方法使用弱引用接收对象,如- (void)someMethod:(id __weak)param
,则不会增加对象的引用计数。 - 返回值:当方法返回一个对象时,如果返回值是强引用类型,调用者接收该返回值会增加对象的引用计数。例如
- (id __strong)createObject { return [[SomeClass alloc] init]; } id __strong result = [self createObject];
,result
会使返回对象的引用计数增加1。如果返回值是自动释放池对象(在ARC下仍然存在自动释放池概念),如- (id)createObject { return [[[SomeClass alloc] init] autorelease]; }
,对象会被放入自动释放池,当自动释放池被销毁时,对象的引用计数会减1 。
- 方法参数传递:当对象作为参数传递给方法时,如果方法内部使用强引用持有该对象,例如
- 赋值场景:
总结
ARC通过编译器自动插入代码,在运行时借助引用计数表跟踪对象引用计数变化。在不同场景如赋值和方法调用中,根据引用类型(强引用、弱引用等)准确地对对象引用计数进行增减操作,从而高效且安全地管理对象的生命周期,避免了手动内存管理容易出现的内存泄漏和悬空指针等问题。