What is the correct way to use realm in an autoreleasepool?
Asked Answered
T

1

11

This is what the documentation has to say about accessing a realm using GCD:

"You should use an explicit autorelease pool when accessing a Realm from a dispatch queue."

Documentation

I have used this practice in my app but I am suddenly seeing the following message in my console: "RLMRealm instance was deallocated during a write transaction".

It is not throwing an error, it is just silently printing it to the console. Nothing is written to the database.

I found this issue on github that seems very similar.

My question is now: What practice should I use? The one used in the Realm documentation or the answer found in the github issue?

Thanks for any clarification.

Turne answered 19/12, 2016 at 9:9 Comment(0)
M
13

GCD blocks manage their own @autorelease pools, but there's no guarantee when that will actually occur, and it may happen a fair amount of time after the block itself has completed (See this SO answer)

Realm maintains read-locks on all of its instances across threads (This is how it's possible to still read from Realm while a write transaction is open on another thread), so as a result, it's recommended to explicitly dealloc a Realm instance when you're done so that disk space can be reclaimed.

If you don't use an @autoreleasepool, nothing too bad will happen; just the size of the Realm file on disk will increase.

Best practice is to use an @autoreleasepool block, and to ensure that all of your write transactions are committed inside that block.

@autoreleasepool {
    let realm = try! Realm()
    try! realm.write {
        // ... perform changes
    }
}

It's usually recommended to use realm.write over beginWrite()/commitWrite() since it lets you safely perform transactions without forgetting to commit, and also provides some extra error handling.

The problem with the issue on GitHub was that there was a logic path that would cause the @autoreleasepool to exit before the write transaction had been committed. In this case, you need to review your code logic and make sure you haven't got anything similar.

Mcgregor answered 19/12, 2016 at 20:3 Comment(8)
nothing too bad will happen; just the size of the Realm file on disk will increase. if it takes too long, your Realm size can increase drastically (depending on the number of concurrent threads), though.Verney
That doesn't apply here. That's when long-running transactions increase the transaction log size. Not draining background Realm instances never drastically increased the size, but it did cause them to grow more than they needed. In any case, we're aware of the transaction log issue and are working on a solution: github.com/realm/realm-core/issues/2343 :)Mcgregor
@Mcgregor would using DispatchQueue(label: "someLabel", autoreleaseFrequency: .workItem).async have the same effect as having an autorelease pool for most cases? Complete question here: #49460467Millrun
@Millrun Hmm, I've never tried that API so I'm not sure. The general idea is you want to make sure the objects are released as soon as possible after the dispatch queue has completed its work. The longer they stay in memory, the longer version pinning occurs (and your Realm file size can grow). In any case, I'd say that's still a far better approach than not having any autoreleasepool handling at all.Mcgregor
We have observed Realm files growing too large to open due to a lack of autoreleasepools around transactions happening on background threads. It's pretty rare that they grow this large, and it likely takes a long time, but it can happen.Definition
Even if we added autoreleasepool the relam files are still growing drastically. Because we have a cache system which is based on realm database. The write transaction is called frequently. So we have to save the cache to the memory first to prevent this problem.Synergy
One thing to keep in mind is that Realm files don't shrink. If you write a lot of data, but then delete it, the Realm file will expand, but won't shrink. This can happen even if you're using an autoreleasepool (But not using one exacerbates the problem), so without knowing more about your code, this might be normal. You should definitely set a clean up policy in your Realm configuration to manage it. This might be worth a new SO question if you still need help. :)Mcgregor
Realm file do shrink, you just have to call compactRealm. For me, it's a cache system, so I just delete all data in the database while the realm initialization is failed to keep my app works well. The file size is still growing very fast even if we have decreased the operations to realm database already.Synergy

© 2022 - 2024 — McMap. All rights reserved.