2

I want to get some insights of Java java.lang.ref.Finalizer initializing process so I set a breakpoint on its class static block:

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();
}

Then start an empty main() method via IntelliJ IDEA debug button, but the breakpoint never stops the program (JVM just executes to its end and exits.)

Java version:

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)

Why this breakpoint not taking effect?

guaner
  • 82
  • 10
  • 1
    Because nothing referenced `Finalizer` so the class was never initialized. – user207421 Sep 19 '21 at 07:18
  • After testing in Intellij and jdb. I found that it can't break at the static block even if we referenced `Finalizer` as `Finalizer` is loaded before main method execute. @guaner, what is the main purpose to debug `Finalizer`? – samabcde Sep 19 '21 at 14:16
  • @user207421 im sure that `Finalizer` has been initialized, because a breakpoint on the empty `main()` thread stops and `jstack` shows there is a `FinalizerThread` thread waiting to do its job. – guaner Sep 19 '21 at 14:35
  • @samabcde im reading the `Finalizer` code to get a deeper understanding of JVM's `finalize()` mechanism. Then I think maybe a step by step debugging helps understanding it more smoothly so i just tried. But unfortunately, it doesn't stop... – guaner Sep 19 '21 at 14:38
  • From [this](https://stackoverflow.com/questions/18214174/how-is-the-java-bootstrap-classloader-loaded), `Finalizer` in `java.lang` is loaded by bootstrap class loader, which is not a java class, this seems to be the reason we can't debug. – samabcde Sep 19 '21 at 14:49
  • @samabcde but some other classes in `java.lang` can be debugged like `Boolean`... maybe I think it's related to the time when `-agentlib:jdwp` kicks in? – guaner Sep 20 '21 at 03:09
  • I mean the static initialisation block can't be debugged, as it runs before main. `Boolean` doesn't have static initialisation block. – samabcde Sep 20 '21 at 03:15
  • 3
    When I run an empty class with `-verbose:class`, the class `Finalizer` is the 38th class to be reported, out of over 400 classes loaded before the main class. Obviously, that’s very early and likely too early to be debuggable. – Holger Sep 20 '21 at 15:59

1 Answers1

1

Since JDK 5.0, the JVM debugging capability has been constructed based on JVM TI which replaces the JVMPI and JVMDI. I'm not familiar with JVMDI thus the following statements are based on the fact you debug the code using agentlib:jdwp like:

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

The jdwp agent (loaded from libjdwp.so file) bind the port specified (5005 in the above example) on receiving post_vm_initialized event. As the event name indicates, VM has been initialized and the Finalizer class has already been loaded when the debug port binding happens (of course you can only debug Java codes after JDWP port listening). So you cannot debug the static block code of Finalizer. In fact, classes loaded before JDWP port binding all are not debuggable in terms of initialization. But if thread runs in the code of the loaded-before classes afterwards, you're still able to debug it, for example the Finalizer.FinalizerThread#run method.

I found a quote from The JVM Tool Interface (JVM TI): How VM Agents Work:

The library is loaded before the VM has initialized, allowing the agent library to capture early VM events that it could not access before.

JDWP agentlib may bind the port on the other hand in Agent_Onload function (in debugInit.c), which may allow the debugging for all classes loading in JVM (I guess).

PS: if you are interested in the code mentioned above (in OpenJDK 8 with Mercurial ID dcb218f54ca1):

  1. post_vm_initialized event processing in function debugInit.c:initialize.
  2. JDWP's Agent_Onload function also locates in code file debugInit.c.
Alaneuler
  • 217
  • 2
  • 11