Memory leaks detected in Kotlin/Native framework when using callback function in iOS development

Viewed 1171

I develop a K/N Multiplatform module and using the latest Kotlin 1.4.21. I found it often shows the following error message and terminate the app (crash) when I deinit this object:

Memory leaks detected, x objects leaked!
Use `Platform.isMemoryLeakCheckerActive = false` to avoid this check.

I cannot not figure out the reason of the memory leak, and following is my kotlin class using callback function:

class Detector(private val onEventDetected: ((event: Event) -> Unit)?) {

    fun processData(data: Data) {
        detectEvent(data)
    }

    private fun detectEvent(data: Data) {
        if (...) {
            ... // some logic
            onEventDetected?.invoke(event)
        }
    }
}

I found when I comment out the onEventDetected?.invoke(event), the error message got disappear. How can I implement the class to forbidden the memory leak issue?

Updated: Dec 21, 2020

I add WeakReference for different platforms:

// Common module
expect class WeakReference<T : Any>(referred: T) {
    fun clear()
    fun get(): T?
}
// For JVM
actual typealias WeakReference<T> = java.lang.ref.WeakReference<T>

// For iOS Native
actual typealias WeakReference<T> = kotlin.native.ref.WeakReference<T>

And update the class:

class Detector(private val onEventDetected: ((event: WeakReference<Event>) -> Unit)?) {

    fun processData(data: Data) {
        detectEvent(data)
    }

    private fun detectEvent(data: Data) {
        if (...) {
            ... // some logic
            onEventDetected?.invoke(WeakReference(event))
        }
    }
}

But the Memory leaks detected issues still happened. There is no clue to solve this problem :(

1 Answers

Original findings:

Hi James, I've seen your sample project and I found out that the leak is due by the lambda when it's set from a thread different from the main thread and having as a parameter a class. If you remove parameters or if you use only primitive types like eventType raw and timestamp the leak doesn't occur. Actually I don't know why this happens, so you could try to file and issue on (youtrack.jetbrains.com) to see if this is a bug or a misuesed pattern. I'm courious about that too.

Update 2021-02-08

We have the official answer:

This is a known problem.

To workaround the problem, please make sure that when your program touches Kotlin code for the first time, it happens on the main thread. For example, declare an empty Kotlin function and call it from applicationDidLoad or whatever. Does it help?

Some of the effects of the problem are fixed in 1.4.30, but not all, so the recommendation above is still valid.

Related