DestroyJavaVM is supposed to wait until all non-daemon threads have exited before starting the shutdown sequence. The logic in Threads::destroy_vm seems to assume that the caller is a non-daemon thread. If the caller is a daemon thread, shutdown will start when one non-daemon thread is still running. See reproducer in attached Main.java and start.c files.