https://kotlinlang.org logo
Title
r

ribesg

04/20/2018, 10:07 PM
Why does this creates TONS of objects, and what should I do to prevent it?
cache.entries.removeAll {
            val res = now - it.value.first > duration
            if (res) <http://log.info|log.info>("Removing value in cache $name for key ${it.key}")
            res
        }
I've got 160k instances of the anonymous class created by the lambda
Is it because it captures parent class parameters ? I don't understand why there's not a single instance of the lambda
o

orangy

04/20/2018, 10:15 PM
depends on the context around it, if there are captured locals, for example
or, if
removeAll
is a Java method, then SAM conversion will create instance each time (I think)
r

ribesg

04/20/2018, 10:20 PM
It's in kotlin.collections.MutableCollections
What should I use instead? I mean a simple iterator and its remove method should work, but I'm trying to keep it clean while removing this huge overhead
o

orangy

04/20/2018, 10:29 PM
I would guess that
now
is what makes it create a capture
but lambda is created only once for the entire operation, is it executed in a loop or something?
r

ribesg

04/20/2018, 10:32 PM
The full method
open fun clear() {
        val now = now
        cache.entries.removeAll {
            val res = now - it.value.first > duration
            if (res) <http://log.info|log.info>("Removing value in cache $name for key ${it.key}")
            res
        }
        errors.entries.removeAll {
            val res = now - it.value.first > errorDuration
            if (res) <http://log.info|log.info>("Removing error in cache $name for key ${it.key}")
            res
        }
    }
now and duration are class properties
o

orangy

04/20/2018, 10:42 PM
yes, but a single call to
clear
should create just two instances of lambdas
r

ribesg

04/20/2018, 10:51 PM
But if I call it twice I get 4 instances? That may explain it
o

orangy

04/20/2018, 10:58 PM
Of course, you capture
now
into a local variable and use it in lambdas. They have to create an instance and capture value in an anonymous class so it is available to the code inside lambda.
It compiles to (pseudocode)
AnonymousClass(val now) : Predicate<Boolean> { override fun invoke() { … you code here … } }
If your collection is always RandomAccess, you can copy implementation from
filterInPlace
(private in stdlib), make it inline, and give it a good name.
Then your lambdas will be inlined and you won’t have any overhead