JDK-8336061 : Virtual threads cannot be GC'ed before they terminate
  • Type: Bug
  • Component: core-libs
  • Affected Version: 21
  • Priority: P4
  • Status: Closed
  • Resolution: Future Project
  • OS: generic
  • CPU: generic
  • Submitted: 2024-07-09
  • Updated: 2024-07-10
  • Resolved: 2024-07-09
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
According to JEP 444, " if a virtual thread is blocked on, e.g., BlockingQueue.take(), and no other thread can obtain a reference to either the virtual thread or the queue, then the thread can be garbage collected — which is fine, since the virtual thread can never be interrupted or unblocked."

It does not work with default setting jdk.trackAllThreads=true, because virtual thread are stored in jdk.internal.vm.ThreadContainers.RootContainer.TrackingRootContainer#VTHREADS

The problem was not exist by default before in https://bugs.openjdk.org/browse/JDK-8302185 jdk.trackAllThreads was enabled by default


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Start example code and take heap dump

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Virtual thread is eligible for garbage collection
ACTUAL -
Virtual thread is accessible from GC root:

io.Demo$AAAConsumer 0x604610278 16 B
	val$task of java.lang.VirtualThread$VThreadContinuation$1 0x604616bd8 40 B
		target of java.lang.VirtualThread$VThreadContinuation 0x604616b38 120 B
			cont of java.lang.VirtualThread 0x604616668 280 B
				key of java.util.concurrent.ConcurrentHashMap$Node 0x604617200 32 B
					java.util.concurrent.ConcurrentHashMap$Node[16] 0x6046171b0 112 B
						table of java.util.concurrent.ConcurrentHashMap 0x604614828 176 B
							map of java.util.concurrent.ConcurrentHashMap$KeySetView 0x604614810 200 B
								VTHREADS of jdk.internal.vm.ThreadContainers$RootContainer$TrackingRootContainer, GC Root: Sticky class 0x604614770 312 B


---------- BEGIN SOURCE ----------
package io;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Demo {

    public static void main(String[] args) throws InterruptedException {
        Thread.ofVirtual().start(new AAAConsumer());
        // here I catch thread/heap dump
        TimeUnit.SECONDS.sleep(15);
    }

    static class AAAConsumer implements Runnable {

        @Override
        public void run() {
            try {
                new ArrayBlockingQueue<>(100).take();
            } catch (InterruptedException e) {
                System.out.println("AAAConsumer interrupted");
            }
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
-Djdk.trackAllThreads=false

FREQUENCY : always



Comments
See: https://mail.openjdk.org/pipermail/loom-dev/2024-July/006830.html In summary, this is essentially a request to add support for ephemeral threads. Project Loom has not closed the door to adding this feature in the future but there are some significant issues to work through before deciding if this supported should be added or not. As regards JEP 444, there is some text copied over from JEP 425 by mistake. We plan to fix that to avoid any confusion.
10-07-2024