【问题标题】:Java Breakpoint set on java.lang.ref.Finalizer not stopped在 java.lang.ref.Finalizer 上设置的 Java 断点未停止
【发布时间】:2021-09-19 05:52:34
【问题描述】:

我想了解一下 Java java.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)

为什么这个断点不生效?

【问题讨论】:

  • 因为没有引用 Finalizer 所以类从未初始化。
  • 在 Intellij 和 jdb 中测试后。我发现即使我们引用了Finalizer,它也不会在静态块处中断,因为在主方法执行之前加载了Finalizer。 @guaner,调试Finalizer的主要目的是什么?
  • @user207421 我确定Finalizer 已被初始化,因为空的main() 线程上的断点停止并且jstack 显示有一个FinalizerThread 线程等待完成其工作。
  • @samabcde 我正在阅读Finalizer 代码以更深入地了解JVM 的finalize() 机制。然后我想也许一步一步的调试有助于更顺利地理解它,所以我只是尝试了。但不幸的是,它并没有停止......
  • 当我使用-verbose:class 运行一个空类时,Finalizer 类是要报告的第 38 个类,在主类之前加载的 400 多个类中。显然,这还为时过早,而且可能还为时过早,无法调试。

标签: java debugging java-8 jdb


【解决方案1】:

从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方法。

我找到了来自The JVM Tool Interface (JVM TI): How VM Agents Work的引用:

该库在 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 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 2010-10-25
    • 1970-01-01
    • 2019-07-09
    • 2021-11-08
    相关资源
    最近更新 更多