Download, link and initialize. When does the class load?

My understanding of class loading was that a class is loaded when it is needed first (to make it very simple). Running the following sample with the -verbose: class and a modified version of the Iterators class that prints a message when its clinic is called, I noticed something that I can’t explain, though:

public class IteratorsTest { public static void main(String[] args) { com.google.common.collect.Iterators.forArray(1, 2, 3); } } 

The output (cleared) is as follows:

 [Loaded com.google.common.collect.Iterators from file:...] [Loaded com.google.common.collect.Iterators$1 from file:...] ---------> Iterators <clinit> 

Why are $ 1 iterators loaded before the clinic call? It is determined only in the clinic, right?

  static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR = new UnmodifiableListIterator<Object>() { ... } 

The result is the following byte code:

 static <clinit>()V L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "---------> Iterators clinit --------------"** INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L1 NEW com/google/common/collect/Iterators$1 DUP INVOKESPECIAL com/google/common/collect/Iterators$1.<init> ()V L2 PUTSTATIC com/google/common/collect/Iterators.EMPTY_LIST_ITERATOR : Lcom/google/common/collect/UnmodifiableListIterator; 

And to confuse me even more, I have another sample (too complicated to post here), where the same line of code, as basically the above, leads to the following output:

 [Loaded com.google.common.collect.Iterators from file:...] ---------> Iterators <clinit> [Loaded com.google.common.collect.Iterators$1 from file:...] 

This is actually what I expected from a simple test program.

I tried to find the answer here https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html , but that really didn't help.

  • What could be the reason that sometimes the clinician is executed first, and sometimes the anonymous class is loaded first?
  • Is there a way to keep track of when the JVM causes class climate? something like -verbose: class or -XX: + TraceClassLoading etc.?
+5
source share
2 answers

Here is a summary of the solution for those who do not want to read all the comments;)

  • The difference in execution order was caused by one of the launchers having -noverify . The verifier can cause the loading of additional classes, also specified here in the JVM Spec . Whether the class is loaded or not seems to depend on the type of field to which the object is assigned. More details here . On the other hand, when starting with -noverify verification is not -noverify , and therefore, the class is loaded only in the place where it is first used in the code that is inside the <clinit> in my case.
  • There are ways to track a <clinit> call without having to change the byte code. One way is to use -XX:+TraceClassInitialization on JDK8. However, this requires a debug version of the JVM (NOTE: this is not your program running in debug mode, but the VM is actually compiled with debugging enabled. A guide to creating it can be found here ). Another way, only with JDK9, is to use the new JEP 158: Unified JVM Logging and provide something like the following when the program starts:
    -Xlog:class+load=info,class+init=info:file=trace.log (see here for how to get a complete list of tags and arguments)
+3
source

What could be the reason that sometimes the clinic is executed first, and sometimes the first class is loaded by an anonymous class?

The class loading process contains the following process.

  • loading
  • stitching
    • check
    • preparation
    • Resolution
  • initialization
  • Using
  • unload

and now we will focus on the resolution and initialization phase for the loaded reference class takes place during the resolution phase , and <clint> is executed at the initialization stage. The order of loading the initialization unloading preparation for downloading the patch is fixed, however, the time when the resolution phase is called is not fixed, it can take place before the initialization phase (correspond to your previous case) and it can also occur after initialization in any scenario (corresponds to your last occasion).

For performance, HotSpot VM typically waits until the class initializes to load and bind the class. Therefore, if class A refers to class B, loading class A will not necessarily result in loading class B (unless this is required for verification). Executing the first command that references B will cause B to initialize, which requires loading and building class B.

Is there a way to keep track of when the JVM causes class climate? something similar to -verbose: class or -XX: + TraceClassLoading, etc.

I don't know if there is any jvm parameter that you can get when the jvm method calls <clinit> directly, but there is another way you can achieve this using jvm_ti . You can listen to some event, for example methodEntry, and then get the method to call time <clinit>. For more information google jvm_ti.

reference :

+5
source

Source: https://habr.com/ru/post/1262819/


All Articles