[External] : Re: Virtual thread memory leak because TrackingRootContainer keeps threads
Alan Bateman
Alan.Bateman at oracle.com
Thu Jul 25 12:54:59 UTC 2024
On 25/07/2024 13:21, Matthew Swift wrote:
> Hmm, I'm starting to think I may have fallen into the same trap here
> as Michal.
>
> I've been using virtual threads similar to platform threads for
> performing IO tasks asynchronously.
>
> Background: originally, I was using
> Executors#newVirtualThreadPerTaskExecutor to run these tasks, which
> was fine because the Executor tracks the virtual threads it creates in
> order to support shutdown. However, from an observability point of
> view I've found the executor to be a bit frustrating because it is
> impossible to set the thread name before the thread is scheduled to
> run[1].
You can specify a ThreadFactory to newThreadPerTaskExecutor so you can
set the thread name if you need it. Virtual threads are meant to be
lightweight and numerous so don't get a name by default. For many cases,
this is okay as the they have a thread ID which will identity them in
thread dumps and elsewhere.
> This means that under heavy load where the FJ pool is busy a thread
> dump shows many unnamed threads, which are waiting to be scheduled for
> the first time. Admittedly, this is only a minor annoyance because I'm
> more interested in the threads that are clogging up the FJ pool than
> the ones which are waiting to use it, even so it'd be nice to have an
> overall picture of what's active and what's queued (note also thread
> names are included in JFR events, which is super helpful).
With the Loom EA builds [1] you can use `jcmd <pid>
Thread.vthread_summary` to get a summary view of all thread grouping so
you get thread counts, a summary of the scheduler, timers, and any
socket I/O that it outstanding. We would like to bring this diagnostic
command into the main line JDK at some point.
>
> To remedy this, I've switched away from using an Executor and now I
> just use "Thread.ofVirtual().name(initialName).start(task)". However,
> I don't think all of the tasks are strongly reachable - some are "fire
> and forget" tasks (e.g. async resource cleanup), so I may be
> inadvertently relying on the JVM's observability support to keep these
> tasks alive until they complete, which seems a bit brittle. In fact,
> now that I think of it, it may not even be limited to fire and forget
> tasks. A VT that is reading messages from a Socket could be GC'd
A virtual thread that is blocked reading from a Socket will continue
when there are bytes to read, the peer closes the connection, some I/O
exception, or the thread is interrupted. So it will be strongly reachable.
-Alan
[1] https://jdk.java.net/loom/
More information about the loom-dev
mailing list