Skip to content

Threads leak when running from Executable Jar #743

@chadselph

Description

@chadselph

Version

2.15.0

Bug description

I'm seeing an issue where using SftpFileSystemProvider to download a file does not release resources, even when reading the file within a try(...) block. However, this only reproduces when I'm running from an executable jar.

Minimal-ish example:

  public static void main(String[] args) throws Exception {
    var uri = args.length == 1 ? URI.create(args[0]) : URI.create(
        // use: docker run -p 2200:22 -v path-to-file:/home/demo/sftp --rm -it emberstack/sftp
        "sftp://localhost:2200/sftp/anyfile.txt"
    );
    for (int i = 0; i < 100; i++) {
      var data = fetchData(uri, "demo", "demo");
      System.out.println(Thread.getAllStackTraces().size() + " threads");
    }
  }

  public static byte[] fetchData(URI url, String user, String pw) throws Exception {
    URI uri = SftpFileSystemProvider.createFileSystemURI(url.getHost(), url.getPort(), user, pw);
    try (FileSystem fs = FileSystems.newFileSystem(uri, Map.of(), Thread.currentThread()
        .getContextClassLoader())) {
      Path remotePath = fs.getPath(url.getPath());
      return Files.readAllBytes(remotePath);
    }
  }

Actual behavior

When I package the app into a jar with the spring boot plugin, which uses a custom classloader, the number of threads increases by 14 with each fetchData call.

./gradlew bootJar && java -jar build/libs/sshd-leak-0.0.1-SNAPSHOT.jar

21 threads
35 threads
49 threads
63 threads
77 threads
91 threads
105 threads
119 threads
133 threads
147 threads
161 threads
175 threads
189 threads
203 threads
217 threads
231 threads

etc. The DirectMemory usage also increases each time, and Spring's docker images annoyingly default DirectMemory to 10MB, so this causes docker images to run out of memory quickly. I've also reproduced this behavior from scala-cli's jar assembly jars, so it isn't completely unique to Spring.

Expected behavior

With spring-boot gradle plugin, when I run ./gradlew bootRun, or just from IntelliJ, everything works as expected:

20 threads
21 threads
22 threads
23 threads
24 threads
25 threads
26 threads
27 threads
28 threads
29 threads
30 threads
30 threads
30 threads
30 threads
30 threads
30 threads
30 threads

The threads grow but they stabilize.

Relevant log output

Other information

I can provide a full, working gradle project if that's helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    sftp_3.0SFTP issues planned to be fixed in version 3.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions