MST
星途 面试题库

面试题:Objective-C中GCD与内存管理及性能优化

在使用Objective-C的GCD进行多任务处理时,如何结合ARC(自动引用计数)来避免内存泄漏?如果在GCD任务中频繁创建和销毁大量对象,应该如何进行性能优化?请详细说明相关原理和实现方式。
13.1万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

结合ARC避免内存泄漏

  1. 原理:ARC负责自动管理对象的内存,当对象的引用计数降为0时,ARC会自动释放对象占用的内存。在GCD中,只要确保任务块(block)对对象的引用在任务执行完毕后正确处理,就可以避免内存泄漏。
  2. 实现方式
    • 避免循环引用:在block中使用__weak关键字修饰可能导致循环引用的对象。例如,假设在一个视图控制器中有一个GCD任务块:
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf) {
            // 在这里使用strongSelf处理任务,这样可以避免block对self的强引用导致循环引用
            // 当block执行完毕,strongSelf的引用计数减1,不会造成self的循环引用
        }
    });
    
    • 正确处理局部对象:在GCD任务块中创建的局部对象,ARC会在任务块执行完毕,对象的作用域结束时自动释放它们,只要不存在不合理的强引用链,就不会发生内存泄漏。

频繁创建和销毁大量对象的性能优化

  1. 原理:频繁创建和销毁对象会导致大量的内存分配和释放操作,这会增加系统开销,影响性能。优化的核心思想是减少不必要的对象创建和销毁,重用对象资源。
  2. 实现方式
    • 对象池
      • 原理:创建一个对象池,预先创建一定数量的对象并存储在池中。当需要使用对象时,从池中获取;使用完毕后,将对象放回池中,而不是销毁它。这样可以减少对象的创建和销毁次数。
      • 实现示例
        // 定义一个对象池类
        @interface ObjectPool : NSObject
        - (id)dequeueObject;
        - (void)enqueueObject:(id)object;
        @end
        
        @implementation ObjectPool {
            NSMutableArray *_pool;
        }
        
        - (instancetype)init {
            self = [super init];
            if (self) {
                _pool = [NSMutableArray array];
                // 预先创建一些对象放入池中
                for (int i = 0; i < 10; i++) {
                    id object = [[YourObjectClass alloc] init];
                    [_pool addObject:object];
                }
            }
            return self;
        }
        
        - (id)dequeueObject {
            if (_pool.count > 0) {
                id object = _pool.lastObject;
                [_pool removeLastObject];
                return object;
            }
            return [[YourObjectClass alloc] init];
        }
        
        - (void)enqueueObject:(id)object {
            [_pool addObject:object];
        }
        
        @end
        
        在GCD任务中使用对象池:
        ObjectPool *pool = [[ObjectPool alloc] init];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            id object = [pool dequeueObject];
            // 使用object进行任务处理
            [pool enqueueObject:object];
        });
        
    • 延迟初始化
      • 原理:只有在真正需要使用对象时才进行初始化,而不是在程序启动或任务开始时就创建所有可能用到的对象。这样可以避免在不需要对象时占用内存,提高程序的启动性能和内存使用效率。
      • 实现示例
        @interface MyClass : NSObject
        @property (nonatomic, strong) ExpensiveObject *expensiveObject;
        - (void)doTask;
        @end
        
        @implementation MyClass
        - (void)doTask {
            if (!_expensiveObject) {
                _expensiveObject = [[ExpensiveObject alloc] init];
            }
            // 使用_expensiveObject进行任务处理
        }
        @end
        
        在GCD任务中:
        MyClass *myObj = [[MyClass alloc] init];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [myObj doTask];
        });