小编Haa*_*ang的帖子

加载,链接和初始化 - 何时加载类?

我对类加载的理解是一个类在第一次需要时被加载(以非常简单的方式放置).使用-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 …
Run Code Online (Sandbox Code Playgroud)

java jvm bytecode classloader static-initializer

7
推荐指数
2
解决办法
1075
查看次数

修补 java.base 会导致 java.lang.LinkageError

-Xbootclasspath/p:path我正在尝试在 Java 11 中做同样的事情,这些事情可以在 java 9 之前的版本中完成。

作为一个简单的示例,我修改了其中一种valueOf方法java.lang.Integer并使用以下方法编译了该项目:

javac --module-source-path=src/java.base --patch-module java.base=src/java.base -d mods $(find src -name '*.java')

然后我使用以下命令运行了一个简单的示例:

java --patch-module java.base=<pathToMyModifiedJavaBaseClasses> -p lib -m my.moduleA/my.moduleA.Main

这很有效,我看到显示的修改(我从 中所做的简单打印valueOf)。

然而,当我尝试做同样的事情时,java.lang.ClassLoader执行程序时出现以下错误(编译有效):

Error occurred during initialization of boot layer java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.invoke.SimpleMethodHandle.

我什至不需要进行更改java.lang.ClassLoader。我的补丁文件夹中该类的绝对存在似乎引发了此错误。(我只想在类的底部添加一个字段)

ClassLoader注意:我只是认为当使用 Eclipse 编译该类时它可以工作。我知道的少数差异之一是 Eclipse 编译器似乎尚未遵循JEP 280invokedynamic但是字节码中也有指令javac,所以我怀疑这就是问题所在。

java classpath java-platform-module-system java-module java-11

4
推荐指数
1
解决办法
619
查看次数

JIT - 微优化 - 如果语句消除

我们假设我们有以下代码:

public static void check() {   
    if (Config.initialized) {
           ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Config.initialized为开头假,只有在某个点的方法已经被JIT已经编译后变为真实.价值永远不会回归假.

我"知道"有很多非常复杂的优化正在进行(循环展开,分支预测,内联,逃逸分析等),虽然我远远没有详细了解它们,但我主要对以下内容感兴趣目前:

  1. JIT编译器是否有办法在某个时间点之后检测到if将始终为true,以便可以完全跳过检查?完全我的意思是没有变量访问,没有条件检查/ jne等...

  2. 如果JIT没有办法摆脱(从某个点开始)不必要的样本检查(我不知道它怎么可能)有什么我可以做的来支持它?我唯一的想法是重新创建类,并在初始化事件发生后从字节代码中删除不必要的代码.

我知道这是完全微观优化,即使使用像JMH这样的工具也可能很难保证,但我仍然想知道和理解.

最后但并非最不重要的:

  1. 我的理解是正确的,如果上面的方法被内联到所有那些方法将被重新编译(假设它们很热),以防某些东西发生变化,以便该check方法需要重新编译?

如果我正确理解我的JitWatch测试结果,上述问题的答案应该是:

  1. 不,没办法.总会有条件检查.
  2. 真的只能通过转型

java jit jvm jvm-hotspot

3
推荐指数
1
解决办法
167
查看次数

调试和正常执行模式之间的不同行为 - WeakReference处理

java.lang.ref.Reference每次调用时,我都修补了类调用自定义本机方法get().修补后的类被添加到引导类路径中.

当我开始一个示例程序时,我看到很多打印输出来自我的本机方法(正如预期的那样),因为ReferenceJDK内部使用了很多s.

奇怪的行为从我的main方法开始.我正在做的就是创建一个WeakReference对象,删除强对象并调用get().无论出于何种原因,我添加的本机方法似乎都没有在运行模式下调用,并且我没有得到任何打印输出,也没有在本机内发生的其他事件.

如果我在调试模式下启动程序,一切都按预期工作,即调用本机方法.

如果我将其更改WeakReference为a SoftReference它始终有效,也可以在正常运行模式下运行.

我甚至尝试添加其他代码(如System.out.printlnget()),但也没有工作.WeakReference在非调试模式下运行时,打印以某种方式停止.在调试中它始终有效.

有时我甚至会Finalizer在关闭期间从我的主要事件中获得很多事件/打印输出.所以看起来这个Reference类看起来有点不同.

java debugging jvm reference

2
推荐指数
1
解决办法
162
查看次数