David
10/16/2018, 8:32 AMDavid
10/16/2018, 8:32 AMclass KotlinNativeFramework {
var listener: KotlinNativeFrameworkListener? = null
fun giveMeDoubles() {
while (true) {
val myList = DoubleArray(100) { 1.0 }.toList()
listener?.listenToDoubles(myList) // If this line is commented, the leak stops.
}
}
}
interface KotlinNativeFrameworkListener {
fun listenToDoubles(list: List<Double>)
}
LeakingClass.m:
#import "LeakingClass.h"
@interface LeakingClass()
@property (nonatomic, strong) KNFKotlinNativeFramework *knf;
@end
@implementation LeakingClass
-(void)start
{
_knf = [KNFKotlinNativeFramework new];
self.knf.listener = self;
[self.knf giveMeDoubles];
}
- (void)listenToDoublesList:(NSArray<KNFDouble *> *)list {}
@end
svyatoslav.scherbina
10/16/2018, 8:37 AMIsn’t it a retain cycle?self.knf.listener = self
David
10/16/2018, 8:39 AMDavid
10/16/2018, 8:43 AMsvyatoslav.scherbina
10/16/2018, 8:44 AMlistenToDoubles
. When calling from Kotlin to Objective-C, Kotlin runtime creates temp Objective-C NSArray
wrapper for Kotlin List
.svyatoslav.scherbina
10/16/2018, 8:45 AMfun giveMeDoubles() {
while (true) {
val myList = DoubleArray(100) { 1.0 }.toList()
autoreleasepool {
listener?.listenToDoubles(myList) // If this line is commented, the leak stops.
}
}
}
David
10/16/2018, 8:54 AMsvyatoslav.scherbina
10/16/2018, 8:57 AMDavid
10/16/2018, 8:59 AMsvyatoslav.scherbina
10/16/2018, 9:00 AMDavid
10/16/2018, 11:33 AMpool = objc_autoreleasePoolPush()
and then I periodically call objc_autoreleasePoolPop(pool)
. Is this best practice or is there another way?olonho
10/16/2018, 11:35 AMsvyatoslav.scherbina
10/16/2018, 11:36 AMDavid
10/16/2018, 11:36 AMsvyatoslav.scherbina
10/16/2018, 11:37 AMsvyatoslav.scherbina
10/16/2018, 11:38 AMDavid
10/16/2018, 11:41 AMsvyatoslav.scherbina
10/16/2018, 11:42 AMobjc_autoreleasePoolPop(pool)
pool = objc_autoreleasePoolPush()
David
10/16/2018, 11:44 AMsvyatoslav.scherbina
10/16/2018, 11:44 AMSo, the best way perhaps is to avoid sending lists to objective-c? If the conversion between lists and NSArrays is the problem…No. Normal Objective-C code uses autorelease pools too. So the necessity to release the pool periodically doesn’t seem to be specific for Kotlin/Native
David
10/16/2018, 11:46 AMsvyatoslav.scherbina
10/16/2018, 11:50 AMautoreleasepool {}
without falling back to its implementation details `objc_autoreleasePoolPop`/`objc_autoreleasePoolPush` with something like this:
while (true) {
autoreleasepool {
repeat(autoreleaseFrequency) {
val myList = DoubleArray(100) { 1.0 }.toList()
listener?.listenToDoubles(myList)
}
}
}
David
10/16/2018, 11:55 AMWorker.execute
to perform work and do the callback. It is then not possible to wrap several event-cycles in one lambda.