MST

星途 面试题库

面试题:Objective-C内存管理机制之专家难度:ARC下的内存管理优化

在ARC(自动引用计数)环境下,虽然大大简化了内存管理,但仍可能存在内存相关问题。请描述一些可能出现的内存隐患场景,并提出相应的优化策略和解决方案,包括但不限于循环引用、内存泄漏检测与修复等方面。
10.8万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

内存隐患场景

  1. 循环引用
    • 场景描述:两个或多个对象相互持有对方的强引用,导致这些对象无法被释放,即使它们在应用程序的其他部分不再被使用。例如,类A有一个属性指向类B的实例,而类B也有一个属性指向类A的实例。
    • 示例代码(以Objective - C为例)
@interface ClassA : NSObject
@property (strong) ClassB *bObject;
@end

@interface ClassB : NSObject
@property (strong) ClassA *aObject;
@end

@implementation ClassA
@end

@implementation ClassB
@end

// 使用时
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.bObject = b;
b.aObject = a;
  1. 延迟释放导致的内存峰值
    • 场景描述:当大量对象被创建且释放时间集中在某一时刻,会导致内存使用量在短时间内大幅上升,可能引发应用程序崩溃或性能问题。比如在滚动视图中一次性加载大量图片,然后在滚动结束时同时释放这些图片对应的对象。
  2. 野指针问题
    • 场景描述:当一个对象被释放后,指向该对象的指针没有被置为nil,其他代码继续使用这个指针访问已释放的内存,这可能导致程序崩溃或未定义行为。例如在ARC环境下,对象被自动释放,但外部指针仍指向原内存地址。
  3. 未释放的系统资源
    • 场景描述:某些对象可能持有系统资源,如文件描述符、网络连接等,ARC只管理对象本身的内存,若对象未正确释放这些系统资源,就会造成资源泄漏。例如一个类负责管理文件读取操作,但在对象销毁时未关闭文件。

优化策略和解决方案

  1. 针对循环引用
    • 使用弱引用或无主引用:在Objective - C中,对于可能产生循环引用的属性,将其中一个设置为weak(适用于对象生命周期可能先于强引用对象结束的情况)或unowned(适用于对象生命周期肯定不会先于强引用对象结束的情况,使用unowned要注意避免野指针问题)。
    • 修改示例代码如下
@interface ClassA : NSObject
@property (weak) ClassB *bObject;
@end

@interface ClassB : NSObject
@property (strong) ClassA *aObject;
@end

@implementation ClassA
@end

@implementation ClassB
@end

// 使用时
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.bObject = b;
b.aObject = a;
  1. 针对延迟释放导致的内存峰值
    • 分批次释放:将对象的释放操作分散在一段时间内进行,避免集中释放。例如在滚动视图场景中,可以在滚动过程中逐步释放不再显示的图片对应的对象。
    • 使用缓存机制:对于频繁创建和释放的对象,可以使用对象池缓存机制,避免反复创建和销毁对象。
  2. 针对野指针问题
    • 使用__weak修饰符:在ARC环境下,声明指针时使用__weak修饰符,当对象被释放时,该指针会自动被置为nil,避免野指针问题。例如__weak id myWeakObject = strongObject;,当strongObject被释放后,myWeakObject会变为nil
  3. 针对未释放的系统资源
    • dealloc方法中释放资源:在对象的dealloc方法中(ARC环境下虽然不需要手动调用dealloc,但可以重写该方法来释放系统资源),关闭文件、断开网络连接等操作。例如在管理文件读取的类中:
@implementation FileManagerClass {
    FILE *file;
}

- (instancetype)initWithFilePath:(NSString *)path {
    self = [super init];
    if (self) {
        file = fopen([path UTF8String], "r");
    }
    return self;
}

- (void)dealloc {
    if (file) {
        fclose(file);
    }
}
@end
  1. 内存泄漏检测
    • 使用 Instruments:在Xcode中,利用Instruments工具的Leaks模板来检测内存泄漏。运行应用程序时,Instruments会实时监控内存使用情况,标记出可能泄漏的内存区域,并显示相关对象的引用链,帮助定位问题代码。
    • 代码审查:定期进行代码审查,重点关注对象的创建和释放逻辑,尤其是涉及到对象间复杂引用关系的部分,确保没有遗漏释放操作或产生循环引用。