I was reading through the PerfMark code and saw a comment about avoid an accidental class load through using reflection in a commit:
if (Boolean.getBoolean("io.perfmark.PerfMark.debug")) {
- Logger.getLogger(PerfMark.class.getName()).log(Level.FINE, "Error during PerfMark.<clinit>", err);
+ // We need to be careful here, as it's easy to accidentally cause a class load. Logger is loaded
+ // reflectively to avoid accidentally pulling it in.
+ // TODO(carl-mastrangelo): Maybe make this load SLF4J instead?
+ Class<?> logClass = Class.forName("java.util.logging.Logger");
+ Object logger = logClass.getMethod("getLogger", String.class).invoke(null, PerfMark.class.getName());
..
}
I don't quite understand which class is prevented from being accidentally loaded here. According to Class#forName will cause the logger class to be loaded. From my understanding, the class will only be loaded if the enclosing if condition is true. Or is this the point I am missing?
Commit with more context is here: https://github.com/perfmark/perfmark/commit/4f87fb72c2077df6ade958b524d6d217766c9f93#diff-f9fdc8ad347ee9aa7a11a5259d5ab41c81e84c0ff375de17faebe7625cf50fb5R116
I ran the part with the if block and set a breakpoint on static and non-static fields in the Logger class. It hit the breakpoint only when the call was executed irregardless of using reflection or direct. When the if condition was false, no logger was loaded in any case.
I think the important point of that commit is to load the classes from
java.util.loggingonly when it is really required (when the system property "io.perfmark.PerfMark.debug" is "true" anderris notnull, i.e. when the classio.perfmark.impl.SecretPerfMarkImpl$PerfMarkImplis not available or that class has not the required constructor.)If the code is
then the
java.util.logging.Loggerclass may be loaded as soon as thePerfMarkclass is verified and linked (since linkingPerfMarkrequires that the static initializer block is executed).With this convoluted code the
java.util.logging.Loggeris only loaded ifPerfMarkcannot load its support classio.perfmark.impl.SecretPerfMarkImpl$PerfMarkImpland the system property "io.perfmark.PerfMark.debug" is set to "true" (which probably means thatjava.util.logging.Loggeris almost never loaded just because you usePerfMark)The JVM Specification has clauses that loading / verifying / linking of a class is not required to load all the referenced classes, and modern JVM implementations will probably implement many of these points to reduce unnecessary class loading and improve performance. But keep in mind that
PerfMarkas a very generic library that supports Java versions from 1.6 to the latest versions probably wants to prevent unnecessary class loading even if the JVM does eagerly load referenced classes.That means that this is a very special technique for a very special library and very special circumstances. If you were to include similar techniques in your code I would object such a change for most places, questioning whether this change is really necessary and supported by rigorous performance tests.