Swift 中大量 Core Data 批量插入的内存泄漏

Posted

技术标签:

【中文标题】Swift 中大量 Core Data 批量插入的内存泄漏【英文标题】:Memory leak with large Core Data batch insert in Swift 【发布时间】:2015-11-09 03:05:18 【问题描述】:

我将数以万计的对象插入到我的核心数据实体中。我有一个NSManagedObjectContext,每次添加对象时我都会在托管对象上下文上调用save()。它可以工作,但是在运行时,内存不断从大约 27M 增加到 400M。并且导入完成后也保持在400M。

有很多关于批量插入的 SO 问题,每个人都说要阅读 Efficiently Importing Data,但它是在 Objective-C 中的,我很难在 Swift 中找到解决这个问题的真实示例。

【问题讨论】:

【参考方案1】:

有几件事你应该改变:

创建一个单独的NSPrivateQueueConcurrencyType 托管对象上下文并在其中异步插入。 插入每个实体对象后不要保存。分批插入对象,然后保存每个批次。批量大小可能是 1000 个对象。 每次批量插入并保存后,使用autoreleasepoolreset 清空内存中的对象。

这是如何工作的:

let managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = (UIApplication.sharedApplication().delegate as! AppDelegate).persistentStoreCoordinator // or wherever your coordinator is

managedObjectContext.performBlock  // runs asynchronously

    while(true)  // loop through each batch of inserts

        autoreleasepool 
            let array: Array<MyManagedObject>? = getNextBatchOfObjects()
            if array == nil  break 
            for item in array! 
                let newObject = NSEntityDescription.insertNewObjectForEntityForName("MyEntity", inManagedObjectContext: managedObjectContext) as! MyManagedObject
                newObject.attribute1 = item.whatever
                newObject.attribute2 = item.whoever
                newObject.attribute3 = item.whenever
            
        

        // only save once per batch insert
        do 
            try managedObjectContext.save()
         catch 
            print(error)
        

        managedObjectContext.reset()
    

应用这些原则使我的内存使用率保持在较低水平,同时也使批量插入速度更快。

进一步阅读

高效导入数据(旧 Apple 文档链接已损坏。如果您能找到,请帮我添加。) Core Data Performance Core Data(大会发帖)

更新

上面的答案完全重写了。感谢 cmets 中的 @Mundi 和 @MartinR 指出我原始答案中的一个错误。并感谢this answer 中的@JodyHagins 帮助我理解和解决问题。

【讨论】:

您的代码中似乎使用的是相同的托管对象上下文,而不是新的。 在我上面的示例中,每个while 循环都会重新创建托管对象上下文。 while 循环代表一批插入,因此单个批次使用相同的托管对象上下文,但下一批会创建一个新的。我过去的问题是我将上下文设为类属性并且从未更改过它。 @Suragch:这取决于managedObjectContext 属性是如何在应用程序委托中实现的,但“通常”的实现是一个惰性属性,它在应用程序的生命周期内创建一次上下文。在这种情况下,您将重用与 Mundi 所说的相同的上下文。 我想进一步了解这些 cmets 的含义,所以我开了一个新问题:Where should NSManagedObjectContext be created? 太棒了——除了自动释放池,我什么都有。谢谢。

以上是关于Swift 中大量 Core Data 批量插入的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

IOS - 如何在 Core Data Swift 中将数据插入到具有关系的不同表中

在Core Data中,如何在swift 4中执行`if exists update else insert`? [复制]

Swift之深入解析如何结合Core Data和SwiftUI

swift 在Core Data中存储Swift值类型

EF Core 慢速批量插入(~80k 行)

Entity Framework Core 7中高效地进行批量数据插入