MST

星途 面试题库

面试题:Objective-C中常见内存泄漏场景及检测方法

在Objective-C编程中,列举至少3种常见的内存泄漏场景,并阐述如何使用 Instruments 工具中的 Leaks 模板来检测这些内存泄漏问题。
28.7万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

常见内存泄漏场景

  1. 对象创建后未释放
    • 当使用 allocnewcopy 方法创建对象时,如果之后没有调用 releaseautorelease,就会导致内存泄漏。例如:
NSString *str = [[NSString alloc] initWithString:@"Hello"];
// 此处没有调用 release 或 autorelease,会造成内存泄漏
  1. 循环引用
    • 两个或多个对象相互持有对方的强引用,形成循环引用,导致对象无法被释放。比如:
@interface ClassA;
@interface ClassB;

@interface ClassA : NSObject
@property (nonatomic, strong) ClassB *classB;
@end

@interface ClassB : NSObject
@property (nonatomic, strong) ClassA *classA;
@end

@implementation ClassA
@end

@implementation ClassB
@end

// 使用时
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.classB = b;
b.classA = a;
// 此时 a 和 b 形成循环引用,都无法释放
  1. 使用 NSTimer 导致的泄漏
    • 如果将 self 作为 NSTimertarget,并且 NSTimer 是在类的实例方法中创建且没有在适当时候 invalidate,会导致 self 无法释放。例如:
@interface MyViewController : UIViewController {
    NSTimer *timer;
}
@end

@implementation MyViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateUI) userInfo:nil repeats:YES];
}
- (void)updateUI {
    // 更新 UI 的代码
}
// 这里没有在 viewWillDisappear 等合适时机调用 [timer invalidate],会造成 self 泄漏
@end
  1. 视图控制器相关泄漏
    • 在视图控制器的视图层级中,如果对视图的引用没有正确管理,例如在视图控制器销毁时,仍然有其他对象持有对该视图控制器视图的强引用,会导致视图控制器及其相关对象无法释放。

使用Instruments工具中的Leaks模板检测内存泄漏问题

  1. 启动Leaks模板
    • 打开Xcode,选择 Product -> Profile,在弹出的 Instruments 模板选择框中,选择 Leaks 模板,然后点击 Profile 按钮。这将启动应用程序,并开始使用 Leaks 工具监控内存泄漏。
  2. 操作应用程序
    • 在应用程序运行过程中,执行可能导致内存泄漏的操作,例如反复创建和销毁可能泄漏的对象,执行循环引用相关的逻辑等。Leaks 工具会实时监测内存使用情况。
  3. 查看Leaks报告
    • Leaks 工具界面主要有两个部分:时间轴和详细信息区域。
    • 时间轴:时间轴上会显示内存使用量的变化曲线,以及检测到的内存泄漏事件的位置。泄漏事件在时间轴上以红色箭头标识。
    • 详细信息区域:当在时间轴上选择一个泄漏事件时,详细信息区域会显示泄漏对象的相关信息,包括对象的类名、分配地址、保留计数等。还会展示对象的内存分配调用栈,通过调用栈可以追溯到对象是在哪个函数或方法中分配的,从而定位到代码中可能导致泄漏的位置。
    • 在详细信息区域的 Call Tree 部分,可以看到函数调用层次结构。可以展开每个节点查看更详细的调用信息,通过分析这些信息可以确定泄漏发生的具体代码位置。例如,如果发现某个 alloc 操作后没有对应的 release,就可以在调用栈中找到对应的 alloc 调用点,进而修改代码修复泄漏问题。
  4. 分析循环引用
    • 对于循环引用导致的泄漏,Leaks 工具可能不会直接明确指出循环引用关系,但通过分析泄漏对象的保留路径(在详细信息区域的 Retain Cycles 部分,如果有循环引用会有相关显示),可以发现对象之间相互持有强引用的情况。通常需要结合代码逻辑,查看对象之间的属性设置等,来确定循环引用的具体形成原因,并通过将其中一个强引用改为弱引用等方式来打破循环引用。