Swift 中的大型 Core Data 批量插入导致内存泄漏
Memory leak with large Core Data batch insert in Swift
我正在将数万个对象插入到我的核心数据实体中。我有一个 NSManagedObjectContext
,每次添加对象时我都会在托管对象上下文上调用 save()
。它可以工作,但是当它是 运行 时,内存从大约 27M 增加到 400M。而且导入完成后还是400M
有很多关于批量插入的 SO 问题,每个人都说要阅读 Efficiently Importing Data,但它在 Objective-C 中,我无法在 Swift 中找到真正的例子来解决这个问题。
您应该更改一些内容:
- 创建一个单独的
NSPrivateQueueConcurrencyType
托管对象上下文并在其中异步插入。
- 插入每个实体对象后不保存。分批插入对象,然后保存每批。批量大小可能类似于 1000 个对象。
- 使用
autoreleasepool
和reset
在每次批量插入和保存后清空内存中的对象。
这可能是这样工作的:
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文档link已损坏。如果您能找到,请帮我添加。)
- Core Data Performance
- Core Data(大会post)
更新
以上答案完全重写。感谢评论中的@Mundi 和@MartinR 指出我原来答案中的错误。并感谢 中的@JodyHagins 帮助我理解和解决问题。
我正在将数万个对象插入到我的核心数据实体中。我有一个 NSManagedObjectContext
,每次添加对象时我都会在托管对象上下文上调用 save()
。它可以工作,但是当它是 运行 时,内存从大约 27M 增加到 400M。而且导入完成后还是400M
有很多关于批量插入的 SO 问题,每个人都说要阅读 Efficiently Importing Data,但它在 Objective-C 中,我无法在 Swift 中找到真正的例子来解决这个问题。
您应该更改一些内容:
- 创建一个单独的
NSPrivateQueueConcurrencyType
托管对象上下文并在其中异步插入。 - 插入每个实体对象后不保存。分批插入对象,然后保存每批。批量大小可能类似于 1000 个对象。
- 使用
autoreleasepool
和reset
在每次批量插入和保存后清空内存中的对象。
这可能是这样工作的:
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文档link已损坏。如果您能找到,请帮我添加。)
- Core Data Performance
- Core Data(大会post)
更新
以上答案完全重写。感谢评论中的@Mundi 和@MartinR 指出我原来答案中的错误。并感谢