RealmSwift 列表项内存泄漏问题
RealmSwift List items memory leak problem
我发现在 iOS 中向 Realm 写入大量数据会导致内存不足和崩溃。经过几天的排查,我发现 Realm 并没有释放一个 List 中不用的对象。我运行下面的例子:
class LeakTestList : Object{
var items = List<LeakTestItem>()
}
class LeakTestItem : Object{
@objc dynamic var data = 0
}
func leakTest()
{
guard let realm = try? Realm() else
{
return
}
let leakTestList = LeakTestList()
leakTestList.items.append(objectsIn: (0..<10000).map{LeakTestItem(value: ["data":[=10=]])})
try? realm.write {
realm.add(leakTestList)
}
}
在leakTest()
return之后,我得到了以下内存配置文件:
LeakTestList
已经消失,但所有项目都保留在内存中。当我试图写很多列表项甚至分成多个足够短的列表时,这会导致内存不足。这是 Realm 的错误还是我可以做些什么来解决这个问题?
我们发现在领域中建立对象,然后以较小的块附加到该对象似乎不仅有助于解决内存中的问题,而且还能显着减小文件大小。
我们的项目必须读取和处理 50Gb 以上的文件,我们发现一次写入大约 1000 个对象似乎是速度、文件大小和内存之间的平衡点。您的里程数可能会有所不同。
我重构了您的代码并添加了几个 for 循环以显示正在发生的事情,但试试这个,看看相比之下内存占用是否更好。
这会以较小的块写入总共 10 个项目,正如我在评论中提到的那样,这会减小整体文件大小。对于您的示例,外部循环为 40,内部循环为 1000。
let leakTestList = LeakTestList()
try? realm.write {
realm.add(leakTestList)
}
var index = 0
for _ in 0..<2 {
var myItems = [LeakTestItem]()
for _ in 0..<5 {
let item = LeakTestItem( value: ["data": index] )
myItems.append(item)
index += 1
}
try? realm.write {
leakTestList.items.append(objectsIn: myItems)
}
}
参考@Jay 的回答,我可以从内存监视器中删除领域对象的内存占用,但内存使用保持不变,直到 viewDidLoad()
结束。经过更多挖掘后,我发现我错过的关键想法是将所有内容都包装在 autoreleasepool
中。参考这篇文章:https://realm.io/docs/cookbook/swift/object-to-background/
func leakTest()
{
autoreleasepool {
guard let realm = try? Realm() else
{
return
}
let leakTestList = LeakTestList()
try? realm.write {
realm.add(leakTestList)
}
try? realm.write {
leakTestList.items.append(objectsIn: (0..<10000).map{LeakTestItem(value: ["data":[=10=]])})
}
}
}
我发现在 iOS 中向 Realm 写入大量数据会导致内存不足和崩溃。经过几天的排查,我发现 Realm 并没有释放一个 List 中不用的对象。我运行下面的例子:
class LeakTestList : Object{
var items = List<LeakTestItem>()
}
class LeakTestItem : Object{
@objc dynamic var data = 0
}
func leakTest()
{
guard let realm = try? Realm() else
{
return
}
let leakTestList = LeakTestList()
leakTestList.items.append(objectsIn: (0..<10000).map{LeakTestItem(value: ["data":[=10=]])})
try? realm.write {
realm.add(leakTestList)
}
}
在leakTest()
return之后,我得到了以下内存配置文件:
LeakTestList
已经消失,但所有项目都保留在内存中。当我试图写很多列表项甚至分成多个足够短的列表时,这会导致内存不足。这是 Realm 的错误还是我可以做些什么来解决这个问题?
我们发现在领域中建立对象,然后以较小的块附加到该对象似乎不仅有助于解决内存中的问题,而且还能显着减小文件大小。
我们的项目必须读取和处理 50Gb 以上的文件,我们发现一次写入大约 1000 个对象似乎是速度、文件大小和内存之间的平衡点。您的里程数可能会有所不同。
我重构了您的代码并添加了几个 for 循环以显示正在发生的事情,但试试这个,看看相比之下内存占用是否更好。
这会以较小的块写入总共 10 个项目,正如我在评论中提到的那样,这会减小整体文件大小。对于您的示例,外部循环为 40,内部循环为 1000。
let leakTestList = LeakTestList()
try? realm.write {
realm.add(leakTestList)
}
var index = 0
for _ in 0..<2 {
var myItems = [LeakTestItem]()
for _ in 0..<5 {
let item = LeakTestItem( value: ["data": index] )
myItems.append(item)
index += 1
}
try? realm.write {
leakTestList.items.append(objectsIn: myItems)
}
}
参考@Jay 的回答,我可以从内存监视器中删除领域对象的内存占用,但内存使用保持不变,直到 viewDidLoad()
结束。经过更多挖掘后,我发现我错过的关键想法是将所有内容都包装在 autoreleasepool
中。参考这篇文章:https://realm.io/docs/cookbook/swift/object-to-background/
func leakTest()
{
autoreleasepool {
guard let realm = try? Realm() else
{
return
}
let leakTestList = LeakTestList()
try? realm.write {
realm.add(leakTestList)
}
try? realm.write {
leakTestList.items.append(objectsIn: (0..<10000).map{LeakTestItem(value: ["data":[=10=]])})
}
}
}