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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions