Skip to content

fix(kotlin): KLS leaves stale idea-system* temp dirs in /tmp, consuming RAM on tmpfs systems #1087

@mareurs

Description

@mareurs

Summary

The Kotlin Language Server (KLS) is built on IntelliJ IDEA's platform. Each KLS instance creates an idea-system* temporary directory under /tmp. These directories are never cleaned up after the language server shuts down, causing unbounded accumulation across test runs.

Observed Impact

On a developer machine with /tmp mounted as tmpfs (RAM-backed — the default on modern Linux systems), repeated test runs accumulated:

329 x idea-system*/  = 30 GiB in RAM
/tmp (tmpfs): 36 GiB used total

Each KLS instance produces ~52 MB in its idea-system* directory. After 329 test sessions the entire tmpfs was nearly exhausted, starving the system of RAM and swap.

Root Cause

IntelliJ's platform runtime defaults to creating its system directory at /tmp/idea-system<random>/ when no explicit idea.system.path JVM property is set. The KotlinLanguageServer currently passes JAVA_TOOL_OPTIONS (heap size) but does not redirect this path:

# src/solidlsp/language_servers/kotlin_language_server.py
def create_launch_command_env(self) -> dict[str, str]:
    env["JAVA_TOOL_OPTIONS"] = jvm_options   # only -Xmx2G by default
    return env

The stop() / _shutdown() implementation in SolidLanguageServer terminates the process but performs no filesystem cleanup.

Suggested Fix

Two complementary changes in KotlinLanguageServer:

  1. Redirect idea.system.path to a location we control (e.g. inside ls_resources_dir or a tempfile.mkdtemp() created at startup) by appending -Didea.system.path=<path> to JAVA_TOOL_OPTIONS.

  2. Clean up on stop — override stop() in KotlinLanguageServer to delete the directory after the process terminates.

Example sketch:

import tempfile, shutil

class KotlinLanguageServer(SolidLanguageServer):
    def __init__(self, ...):
        self._idea_system_dir = tempfile.mkdtemp(prefix="serena-idea-system-")
        ...

    def create_launch_command_env(self) -> dict[str, str]:
        env = super().create_launch_command_env()
        jvm_options = env.get("JAVA_TOOL_OPTIONS", "")
        env["JAVA_TOOL_OPTIONS"] = f"{jvm_options} -Didea.system.path={self._idea_system_dir}".strip()
        return env

    def stop(self, shutdown_timeout: float = 2.0) -> None:
        super().stop(shutdown_timeout)
        if hasattr(self, "_idea_system_dir"):
            shutil.rmtree(self._idea_system_dir, ignore_errors=True)

Alternatively the directory can live under ls_resources_dir/kotlin_language_server/system/ — a persistent but bounded cache — if keeping the IntelliJ index across sessions is desirable (faster restarts). In that case no cleanup is needed, but its size should be documented.

Environment

  • Platform: Linux (x86-64), /tmp is tmpfs
  • KLS version: 261.13587.0 (default bundled)
  • Serena branch: fix/kill-gradle-daemons-on-shutdown

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions