Ricky Mo
Ricky Mo

Reputation: 7648

RealmSwift List items memory leak problem

I found writing huge amount of data to Realm in iOS causes out of memory and crash. After days of investigation, I found that Realm does not release unused objects in a List. I ran the following example:

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":$0])})
    try? realm.write {
        realm.add(leakTestList)
    }
}

After leakTest() return, I got the following memory profile:

Realm memory leak test

LeakTestList has already gone but all the items remains in memory. This cause out of memory when I tried to write a lot of list items even divided into multiple short enough lists. Is this a bug from Realm or is there anything I can do to solve the problem?

Upvotes: 2

Views: 1967

Answers (2)

Ricky Mo
Ricky Mo

Reputation: 7648

Referring to @Jay 's answer, I am able to remove the memory footprint of the realm objects from the memory monitor, but the memory usage stay the same until viewDidLoad() end. After more digging, turns out the key idea I missed was to wrap everything in autoreleasepool. Referring to this article : 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":$0])})
        }
    }
}

Upvotes: 1

Jay
Jay

Reputation: 35657

We find that establishing the object in realm and then appending to that object in smaller chunks seems to not only help with in-memory issues but also significantly reduces the file size.

Our project had to read and process files that were 50Gb+ and we found that writing about 1000 objects at a time seemed to be the balance point between speed, file size and memory. Your milage may vary.

I refactored your code and added a couple of for loops to show what's going on but try this out and see if the memory footprint is better by comparison.

This writes 10 total items in smaller chunks which, as mentioned in my comment, reduces the overall file size. for your example the outside loop would be 40 and the inside would be 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)
    }
}

Upvotes: 0

Related Questions