Has anyone else experienced issues with NSObjects ...
# kotlin-native
s
Has anyone else experienced issues with NSObjects not being deallocated properly? I have a function that is called in a loop which allocates an NSObject (NSProcessInfo) but it never gets deallocated My loop runs for 150 ms and during that time application memory usage typically rises by ~50 MB, and when profiling I see it is because there are thousands of NSProcessInfo objects that never get deallocated (each one is only 4 KB)
Copy code
fun elapsedRealtime() = (NSProcessInfo().systemUptime * 1_000)

val startTime = elapsedRealtime()
var currentTime = startTime
while (currentTime - startTime < 150) {
    currentTime = elapsedRealTime()
}
I would think NSProcessInfo objects should automatically be deallocated each time
elapsedRealtime
completes since the reference count would be 0, but I am unsure how Kotlin’s GC interacts with Swift/Objective-C’s ARC If I change the loop to run for 25 seconds for example my memory usage shoots up nearly 500 MB. This is running on macOS 10.14.6
FWIW, I was able to greatly decrease the memory footprint by surrounding the function in an autorelease pool, but it still seems to hold onto a bunch of the objects without releasing, just less than before
fun elapsedRealTime() = autoreleasepool { NSProcessInfo().systemUptime * 1_000 }
In this case I can run for 25 seconds and only increase memory by about 7 MB (as opposed to 500 MB previously), but still that 7 MB never goes away after the fact
o
insert GC call
<https://github.com/JetBrains/kotlin-native/blob/8e0e346492436cc9c40d87f38926e841954d1d4e/runtime/src/main/kotlin/kotlin/native/internal/GC.kt#L30>
if you need to force collection, K/N uses delayed reference counter, so some memory may add up
s
@olonho I have tried that and it does not free up any of the memory
I even tried calling
GC.start()
first since it says collect will not do anything if it is stopped
o
How do you measure?
s
Mac Activity Monitor
Shows the memory gradually go up to 500 MB as soon as my loop starts, and the program continues to execute afterwards but memory never goes down even after GC collect call
I am writing a framework that is used in Swift as well and using the Xcode profiler to view allocations I see that the
@autoreleasepool content
section is never cleared
@olonho Created a gist, maybe you can try to reproduce with it? https://gist.github.com/sschilli/5692c4582a85daec9a3ace186d8b431c
I just came across something interesting… if I call
GC.collect
after the loop body, memory usage grows very quickly, up to 500 MB:
Copy code
while (currentTime - startTime < 25_000L) {
    currentTime = timer.elapsedRealtime()
}
GC.collect()
However if I call it inside the loop body, it grows much slower, up to only 8 MB by the time 25 seconds expires:
Copy code
while (currentTime - startTime < 25_000L) {
    currentTime = timer.elapsedRealtime()
    GC.collect()
}
Can anyone explain this disparity?
@olonho I didn’t think GC.collect would be context dependent?
Seems to imply a memory leak
Either way though memory usage continues to grow unbounded despite GC.collect call, just because NSProcessInfo isn’t deallocated properly
o
Please file an issue, but note, that macOS memory manager doesn’t guarantee, that even after freeing OS footprint reduces, so real marker if leak is evergrowing memory usage or seen in analysis by tools like valgrind