Java断点设置在Java .lang.ref. finalizer未停止



我想了解一些Javajava.lang.ref.Finalizer初始化过程,所以我在它的类静态块上设置了一个断点:

static {
->    ThreadGroup tg = Thread.currentThread().getThreadGroup(); // breakpoint set on this line
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread finalizer = new FinalizerThread(tg);
finalizer.setPriority(Thread.MAX_PRIORITY - 2);
finalizer.setDaemon(true);
finalizer.start();
}

然后通过IntelliJ IDEA调试按钮启动一个空的main()方法,但是断点永远不会停止程序(JVM只是执行到它的结束并退出)

Java版本:

openjdk version "1.8.0_302"
OpenJDK Runtime Environment Corretto-8.302.08.1 (build 1.8.0_302-b08)
OpenJDK 64-Bit Server VM Corretto-8.302.08.1 (build 25.302-b08, mixed mode)

为什么这个断点不生效?

从JDK 5.0开始,JVM调试功能已经基于JVM TI构建,取代了JVMPI和JVMDI。我不熟悉JVMDI,因此以下语句是基于您使用agentlib:jdwp调试代码的事实,如:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005

jdwp代理(从libjdwp.so文件加载)在接收post_vm_initialized事件时绑定指定的端口(在上面的示例中为5005)。正如事件名称所示,当调试端口绑定发生时,VM已经初始化并且Finalizer类已经加载(当然,您只能在JDWP端口侦听之后调试Java代码)。因此,您无法调试Finalizer的静态块代码。实际上,在JDWP端口绑定之前加载的类在初始化方面都是不可调试的。但是,如果线程在之后加载之前的类的代码中运行,您仍然可以调试它,例如Finalizer.FinalizerThread#run方法。

我找到了JVM工具接口(JVM TI)的引用:VM代理如何工作:

在VM初始化之前加载库,允许代理库捕获以前无法访问的早期VM事件。

JDWP agentlib可以在Agent_Onload函数中绑定端口(在debugInit.c中),这可能允许在JVM中加载所有类的调试(我猜)。

PS:如果您对上面提到的代码感兴趣(在OpenJDK 8中,Mercurial ID为dcb218f54ca1):

  1. post_vm_initialized事件处理函数debugInit.c:initialize.
  2. JDWP的Agent_Onload函数也位于代码文件debugInit.c

最新更新