Haa*_*ang 7 java jvm bytecode classloader static-initializer
我对类加载的理解是一个类在第一次需要时被加载(以非常简单的方式放置).使用-verbose:class和Iterators类的修改版本运行以下示例,该类在调用其clinit时打印消息我观察到了一些我无法解释的内容:
public class IteratorsTest
{
public static void main(String[] args)
{
com.google.common.collect.Iterators.forArray(1, 2, 3);
}
}
Run Code Online (Sandbox Code Playgroud)
(清理)输出如下:
[Loaded com.google.common.collect.Iterators from file:...]
[Loaded com.google.common.collect.Iterators$1 from file:...]
---------> Iterators <clinit>
Run Code Online (Sandbox Code Playgroud)
为什么在调用clinit之前加载Iterators $ 1?它只在临床中定义,不是吗?
static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR =
new UnmodifiableListIterator<Object>() {
...
}
Run Code Online (Sandbox Code Playgroud)
这导致以下字节代码:
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;
Run Code Online (Sandbox Code Playgroud)
为了让我更加困惑,我还有一个样本(太复杂了,无法在此处发布),其中与上面主要内容相同的代码行导致以下输出:
[Loaded com.google.common.collect.Iterators from file:...]
---------> Iterators <clinit>
[Loaded com.google.common.collect.Iterators$1 from file:...]
Run Code Online (Sandbox Code Playgroud)
这实际上也是我对简单测试程序的期望.
我试着在这里找到答案https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html,但这并没有真正帮助.
有时候诊所首先被执行,有时候匿名类首先被加载的原因是什么?
类加载过程包含以下过程.
现在我们关注加载的引用类的分辨率和初始化阶段发生在分辨率阶段,<clint>发生在初始化阶段.加载修改准备初始化卸载的顺序是固定的,但是调用解析阶段的时间不固定,它可能发生在初始化之前(对应你的前一种情况)阶段,也可能发生在某些情况下的初始化之后(对应后者)案件).
为了提高性能,HotSpot VM通常会等到类初始化以加载和链接类.因此,如果类A引用类B,则加载类A不一定会导致加载类B(除非验证需要).执行引用B的第一条指令将导致B的初始化,这需要加载和链接B类.
有没有办法跟踪JVM何时调用类的临时?类似于-verbose:class或-XX:+ TraceClassLoading等?
我不知道是否存在一些jvm参数,你可以获得jvm直接调用<clinit>方法的时间,但还有另一种方法可以实现这一点,使用jvm_ti.你可以听一些像methodEntry这样的事件,然后调用<clinit>方法.有关更多信息,请访问google jvm_ti.
参考:
这里是那些不想阅读所有评论的人的解决方案摘要;)
-noverify指定的启动程序引起的.验证程序可能会导致加载其他类,如JVM规范中所述.无论是否加载类,似乎都取决于对象所分配的字段的类型.更多细节在这里.另一方面,当开始时-noverify,没有验证,因此类的加载仅发生在代码中首次使用的位置,<clinit>在我的情况下.<clinit>而无需修改字节代码.一种方法是使用-XX:+TraceClassInitializationon JDK8.但是,这需要JVM的调试版本(注意:这不是您的程序在调试模式下启动,但实际上是在启用调试的情况下编译的VM.可以在此处找到有关如何构建它的指南).另一种方式 - 只提供JDK9 - 是使用新的JEP 158:统一JVM日志记录功能,并在启动程序时提供类似以下内容:( -Xlog:class+load=info,class+init=info:file=trace.log请参阅此处了解如何获取完整的标记和参数列表)| 归档时间: |
|
| 查看次数: |
1075 次 |
| 最近记录: |