Memory leak in KotlinCoreEnvironment and KotlinToJVMBytecodeCompiler

When trying to compile on-disk Kotlin code to class files, everything works great, except there is a memory leak.

I’ve created a simple project (in Java) to reproduce the problem:

The key code is the following:

        ParentDisposable parentDisposable = new ParentDisposable();
        KotlinCoreEnvironment env = KotlinCoreEnvironment.createForProduction(
                parentDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
        GenerationState result = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(env);

After running this, I tried disposing the resources:

            Disposer.dispose(parentDisposable);
            KotlinCoreEnvironment.Companion.disposeApplicationEnvironment();

Without running the Disposer code, there is a heap memory leak, which appears to be coming from the org.jetbrains.kotlin.metadata package.

Alternatively, by running the Disposer code, the heap memory leak doesn’t happen to the same degree, but instead there is a metaspace leak with more and more classes becoming loaded.

There is a similar issue discussed here, except in the context of a Kotlin script engine, which I’m not using:

What is the correct way to invoke the an embedded Kotlin compiler, to generate class files from source code, and correctly disposing it without a memory leak?

Thos things are better reported directly to https://youtrack.jetbrains.com/issues/KT

1 Like

I’m not sure that this is a bug, maybe I’m just not using the API correctly?

I couldn’t find any examples of this online, even just the following code results in a metaspace leak:

val configuration = CompilerConfiguration()
configuration.put(MODULE_NAME, "test")
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, NONE)

for (i in 0 .. 1_000_000) {
    val parentDisposable = Disposer.newDisposable()
    KotlinCoreEnvironment.createForProduction(
        parentDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
    Disposer.dispose(parentDisposable)
}

As suggested, I opened an issue: https://youtrack.jetbrains.com/issue/KT-47044