MST
星途 面试题库

面试题:Objective-C对象销毁时的内存管理及相关机制

当Objective-C对象销毁时,ARC(自动引用计数)和MRC(手动引用计数)分别是如何管理内存的?请深入分析ARC的工作原理,以及在ARC环境下可能出现的内存泄漏场景及解决方案。
42.0万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

ARC(自动引用计数)管理内存方式

  • 对象销毁时:ARC 会在对象的引用计数降为 0 时,自动释放该对象占用的内存。编译器会在编译期自动插入适当的内存管理代码,例如 retain、release 和 autorelease 等操作。
  • 工作原理
    • 编译期处理:编译器会分析代码中对象的生命周期,在适当的位置插入内存管理的调用。当对象被创建或被赋值给一个新的变量时,引用计数增加;当对象的作用域结束或者变量被赋值为 nil 时,引用计数减少。
    • 运行时机制:ARC 依赖运行时系统来跟踪对象的引用计数。运行时系统会维护一个引用计数表,记录每个对象的引用计数。当引用计数变为 0 时,运行时系统会自动调用对象的 dealloc 方法来释放内存。

MRC(手动引用计数)管理内存方式

  • 对象销毁时:在 MRC 中,开发者需要手动调用 release 方法来减少对象的引用计数。当引用计数降为 0 时,对象会自动调用 dealloc 方法释放内存。如果开发者忘记调用 release 方法,就会导致内存泄漏。

ARC 环境下可能出现的内存泄漏场景及解决方案

  1. 循环引用
    • 场景:两个或多个对象相互强引用,导致它们的引用计数永远不会降为 0。例如,对象 A 持有对象 B 的强引用,对象 B 又持有对象 A 的强引用。
    • 解决方案:使用弱引用(weak)或无主引用(unowned)来打破循环引用。在上述例子中,可以将其中一个引用改为 weak 或 unowned。如果对象 B 可能为 nil,可以使用 weak;如果对象 B 不会为 nil,可以使用 unowned。
  2. NSTimer 导致的泄漏
    • 场景:如果使用 scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 方法创建 NSTimer,并且 target 是 self,由于 NSTimer 对 target 持有强引用,而 self 又对 NSTimer 持有强引用,就会导致循环引用。
    • 解决方案
      • 使用 block 形式的 NSTimer 初始化方法 scheduledTimerWithTimeInterval:repeats:block:,这样可以避免强引用 target。
      • 或者在适当的时候手动 invalidate NSTimer,并将其设置为 nil。
  3. Block 导致的泄漏
    • 场景:如果 block 内部使用了 self,并且 block 被强引用,就会形成循环引用。例如,在 viewController 中定义一个 block 属性,并在 block 内部访问 self 的属性。
    • 解决方案:使用 weak 或 strong 关键字修饰 self。一般先使用 __weak typeof(self) weakSelf = self;,然后在 block 内部使用 weakSelf。如果需要在 block 内部保持 self 的生命周期,可以在 block 内部再使用 __strong typeof(weakSelf) strongSelf = weakSelf;