【发布时间】:2017-05-30 02:49:48
【问题描述】:
我对类加载的理解是,一个类在第一次需要时被加载(用一种非常简单的方式说)。使用 -verbose:class 和 Iterators 类的修改版本运行以下示例,该版本在调用其 clinit 时会打印一条消息,但我观察到了一些我无法真正解释的事情:
public class IteratorsTest
{
public static void main(String[] args)
{
com.google.common.collect.Iterators.forArray(1, 2, 3);
}
}
(清理后的)输出如下:
[Loaded com.google.common.collect.Iterators from file:...]
[Loaded com.google.common.collect.Iterators$1 from file:...]
---------> Iterators <clinit>
为什么在调用 clinit 之前加载 Iterators$1?它只在 clinit 中定义,不是吗?
static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR =
new UnmodifiableListIterator<Object>() {
...
}
这会产生以下字节码:
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;
更让我困惑的是,我还有一个示例(太复杂,无法在此处发布),其中与上面主要代码中的代码行相同的代码导致以下输出:
[Loaded com.google.common.collect.Iterators from file:...]
---------> Iterators <clinit>
[Loaded com.google.common.collect.Iterators$1 from file:...]
这实际上也是我对简单测试程序的期望。
我试图在这里找到答案 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html ,但这并没有真正帮助。
- 有时先执行 clinit 而有时先加载匿名类的原因是什么?
- 当 JVM 调用类的 clinit 时,有没有办法跟踪?类似于 -verbose:class 或 -XX:+TraceClassLoading 等的东西?
【问题讨论】:
-
openjdk9 的新日志基础设施允许对许多内部结构进行相当细粒度的分解,包括类加载和初始化。也许这会提供你想要的信息。
-
好主意,我了解了新的日志记录功能,但还没有尝试过。也许值得进行试运行。谢谢!
-
虽然我找到了它,但我想知道 JDK9 是否会有所帮助,是的,确实可以完成这项工作。我从 -Xlog:class+init=info,class+load=info:file=trace.log 开始(顺便说一句:某处是否有可用选择器的完整列表?这里提供的 openjdk.java.net/jeps/158 还不够)。 PS:实际上是你在这里的评论stackoverflow.com/questions/39321345/… 我第一次读到这个。
标签: java jvm classloader bytecode static-initializer