Is there any "official" documentation on Embedded ...
# scripting
l
Is there any "official" documentation on Embedded (as in, JVM-Embedded, not microcomputer-embedded) kotlin-scripting with or without JSR223? is there any documentation on JSR223? The only way I was able to use this feature is by following some old blog-posts and issue-threads, I've never stumbled upon actual documentation. And I'm having a lot of problems with my scripting (it seems to not clean up any memory, -> memory-leak that i don't know how to prevent)) and I have no idea where to find out what I'm doing wrong. many of these problems here seem to come from a point of "I read a few blog-posts, now it isn't working the same way as i'm using a different language or context, what do i do"....
i
Unfortunately, there is no official documentation for kotlin scripting yet. There are some examples, and we're going to announce some more of them soon, but the documentation is definitely missing. As of the memory leaks, they could be caused by the JSR-223 usage - there were detailed explanations in this channel, but in short - JSR-223 engine is a REPL, and therefore keeps complete compilation and evaluation state, which of course increased with every
eval
call. So, if REPL is not something you need or want, you either can recreate an engine for every
eval
or use scripting API instead.
l
Do you have some resources for the scripting API (non-JSR-233)? I'm definitely not bound to use JSR223, it's just the only thing i was able to find any resources about at all. The thing is, I current AM creating a new engine every eval call, but still leaking memory.
i
Here is not yet official site with examples that could be helpful - https://github.com/Kotlin/kotlin-script-examples
The thing is, I current AM creating a new engine every eval call, but still leaking memory.
This is interesting. Do you have more info? The rate of leaking? Maybe a memory snapshot or code sample to analyze?
l
It's a very strange issue, as it does not show up in any Profiling tools / heap-dumps I've done as of now. The memory usage just steadily increases with every eval. The only way I know it's related to scripting is that if I eval only once, no memory-increase is seen. but I was unable to actually find out anything more specific about it. The problem seems to be more extreme when running in a Docker-container, but that could also just be the JVM crashing a lot later as there is more Ram than on my Dev-machine...
i
Hmm, not good. If you will get any insights into it, please file an issue. Seems we need to investigate it further.
l
If I find the time, I'll try to create a minimal version reproducing the issue. for now I'll look into your kotlin Scripting link! Thanks a lot!
­čĹŹ 2
So I'm trying to create a minimal example by trying to create something that at least somewhat resembles my usecase, but just filling it with a lot more data to accelerate the occurrence of the problem. After somewhat limiting the JVMs heap memory (
-Xmx200m
) I'm quickly running into
OutOfMemoryError: GC overhead limit exceeded
with this code:
Copy code
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import javax.script.ScriptEngineManager
import kotlin.random.Random

fun main() {
    setIdeaIoUseFallback()
    val dsl = """
        createFamily {
            person {
                name = "tom"
                age = 12
            }
        }
    """
    repeat(10000) {
        val scriptEngine = ScriptEngineManager().getEngineByExtension("kts")!!
        val family = scriptEngine.eval(dsl) as Family
        println(family)
    }
}

fun createFamily(build: FamilyBuilder.() -> Unit) = FamilyBuilder().apply(build).create()
data class Family(val people: List<Person>)

class FamilyBuilder() {
    private val people = mutableListOf<Person>()
    fun person(build: PersonBuilder.() -> Unit) {
        people.add(PersonBuilder("", 0).apply(build).create())
    }
    fun create() = Family(people)
}

data class Person(val name: String, val age: Int) {
    // just some large object to speed up garbage-production
    private val bigData: ByteArray = Random.Default.nextBytes(1_000_000)
}
class PersonBuilder(var name: String, var age: Int) {
    fun create() = Person(name, age)
}
I'm not sure if this should work, but my feeling is that if i create an instance in a loop, print it out and then ignore it, the GC should be able to collect it easily and have no problem here. I know I'm creating a lot of garbage data here, so the "GC overhead limit exceeded" error could just stem from it having to do to much, but I'm also getting the same error in my actual usecase, just a lot slower as there is less garbage created a lot slower.
j
A guess with no facts to back it up: you don't ever exit the method in which you are allocating all the objects. Put the inside of the repeat() inside a method. Does it make a difference?
l
I've tried, didn't change anything. Also, I wouldn'ht have thought it would, because it does work with not problem when not using the Scripting stuff (just calling the functions directly