Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On JVM worker threads retain context class loader #3832

Closed
dovchinnikov opened this issue Jul 31, 2023 · 2 comments
Closed

On JVM worker threads retain context class loader #3832

dovchinnikov opened this issue Jul 31, 2023 · 2 comments
Assignees
Labels

Comments

@dovchinnikov
Copy link
Contributor

Describe the bug

If a thread happens to start from a thread with different context class loader, then the class loader is retained for an unforeseeable time (at least for IDLE_WORKER_KEEP_ALIVE_NS, may be longer under load). In multi-loader environment this causes a leak.

Provide a Reproducer

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MyClassLoader : ClassLoader()

fun main() {
  val custom = MyClassLoader()
  runBlocking {
    val current = Thread.currentThread().contextClassLoader
    try {
      Thread.currentThread().contextClassLoader = custom
      launch(Dispatchers.Default) {} // spawn new thread
    }
    finally {
      Thread.currentThread().contextClassLoader = current
    }
  }
  println("A place for breakpoint")
}
image
@dovchinnikov
Copy link
Contributor Author

dovchinnikov commented Jul 31, 2023

Similar leak in IJ thread pools: https://youtrack.jetbrains.com/issue/IDEA-239033, I think coroutine scheduler pool is also prone to that, although I cannot provide reliable repro.

Edit: IJ platform fix of this problem JetBrains/intellij-community@20931fc

@qwwdfsad qwwdfsad self-assigned this Sep 4, 2023
@qwwdfsad
Copy link
Member

qwwdfsad commented Sep 4, 2023

The behaviour of Dispatchers.Default mimics any other executor on the JVM -- the threads are created in the current thread context classloader. Typically, it's possible to work around it by supplying your own ThreadFactory, but not for the "global" dispatcher that relies on a specific thread subclass.

It seems like it makes sense to set the thread's context to the same context classloader as the Dispatchers.Default itself, but I would like you to confirm it fixes the issue for you

qwwdfsad added a commit that referenced this issue Sep 4, 2023
…s the dispatcher itself

In order to properly operate in modularized on a classloader level environments with the absence of other workarounds (i.e. supplying application-specific thread factory)

Fixes #3832
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants