You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NSOperationQueue调用waitUntilAllOperationsAreFinished导致实例晚释放问题

根因分析

使用waitUntilAllOperationsAreFinished时出现内存释放延迟的核心原因有两个:

  1. 该方法会阻塞当前调用线程,线程关联的自动释放池需要等到线程从阻塞状态恢复、完成当前所有任务后才会执行内存回收,已经执行完成的Operation实例会被临时暂存在释放池中,无法即时释放。
  2. 你当前CustomOperation的main方法中,asyncAfter闭包强持有了Operation实例本身,也会拉长实例的持有周期。

解决方案

方案1:替换阻塞等待逻辑(推荐,无性能损耗)

完全不需要使用waitUntilAllOperationsAreFinished阻塞线程,通过添加依赖收尾操作的方式实现"所有任务完成后执行指定逻辑"的需求,同时保证每个Operation执行完毕就立即释放:

DispatchQueue.global().async {
    // 定义收尾操作,所有业务操作完成后才会执行
    let finishOperation = BlockOperation {
        print("All Tasks Done")
    }
    
    (0...5).forEach {
        let customOp = CustomOperation(value: $0)
        // 给收尾操作添加依赖,确保所有业务操作跑完才执行收尾逻辑
        finishOperation.addDependency(customOp)
        self.queue.addOperation(customOp)
    }
    
    self.queue.addOperation(finishOperation)
}

该方案既满足你的业务需求,还不会浪费线程资源做无意义的阻塞,是Operation队列的标准最佳实践。

方案2:保留wait逻辑的优化方式

如果必须使用waitUntilAllOperationsAreFinished,可以通过两个修改实现即时释放:

  1. 修复CustomOperation中的循环引用,将asyncAfter闭包对self的强引用改为弱引用
  2. 在添加Operation的逻辑外层包裹局部自动释放池

修改后的CustomOperation相关代码:

override func main() {
    print("Begin Task \(value)")
    DispatchQueue.global().asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(value)) { [weak self] in
        guard let self = self else { return }
        print("Finish Task \(self.value)")
        self.finish()
    }
}

修改后的调用逻辑:

DispatchQueue.global().async {
    (0...5).forEach { value in
        autoreleasepool {
            self.queue.addOperation(CustomOperation(value: value))
        }
    }
    self.queue.waitUntilAllOperationsAreFinished()
    print("All Tasks Done")
}

以上两个方案都可以实现Operation执行完毕后立即触发deinit,不会等到所有任务全部完成再释放。

内容的提问来源于stack exchange,提问作者anb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 16:54:04