realm-kotlin
realm-kotlin copied to clipboard
RealmResults leak
How frequently does the bug occur?
Sometimes
Description
In specific cases notification callback is not released that leads to memory leaks. A notification callback holds a reference to RealmResults that I believe holds reference to native realm results.
The leak happens when a Flow that returned from ObjectQuery::asFlow() is cancelled before callbackFlow() (source) execution reaches awaitClose() (source). It that case notification token that was received in RealmResults::registerForNotification won't be released.
This leak can be verified by capturing memory heap dump. NativeObjectReference, RealmResultsImpl instances left after closing everything and calling GC. Only a reference to callback holds reference to RealmResultsImpl.
I think it can be fixed by surrounding withContext(dispatcher) { ... } by try catch that catches CancellationException and releases a notification token if needed:
return callbackFlow {
//...
try {
withContext(dispatcher) {
//...
}
} catch (err: CancellationException) {
token.value.cancel()
throw err
}
awaitClose {
// ...
}
}
Stacktrace & log output
No response
Can you reproduce the bug?
Sometimes
Reproduction Steps
This bug can be reproduced by creating many observers and cancelling them in a loop.
private fun observe() {
lifecycleScope.launch {
(0..100).forEach {
val jobs = observeMany()
delay(100)
jobs.cancel()
delay(100)
}
}
}
private fun observeMany(): Job {
return lifecycleScope.launch {
val flows = (0..100).map { idx ->
realm!!.query(Entity0::class)
.query("column1 >= $0", 4000 + idx * 100)
.asFlow()
.map { it.list }
}
combine(flows) { arr -> arr }
.collect {
Log.d("!!!!!", "Realm observed many Entity0")
}
}
}
Version
3.0.0
What Atlas App Services are you using?
Local Database only
Are you using encryption?
No
Platform OS and version(s)
Android 15
Build environment
Android Studio version: 2023.3.1 Patch 2 Android Build Tools version: 8.3.2 Gradle version: 8.4