Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JVM什么时候考虑字节码优化的代码?_Java_Performance_Bytecode_Jvm Hotspot - Fatal编程技术网

Java JVM什么时候考虑字节码优化的代码?

Java JVM什么时候考虑字节码优化的代码?,java,performance,bytecode,jvm-hotspot,Java,Performance,Bytecode,Jvm Hotspot,我试图理解JVM和热点优化器的内部结构 我尽可能快地处理初始化具有大量节点的对象树结构的问题。 现在,对于给定的每个树结构,我们生成Java源代码来初始化树,如下所示。最后,我们有数千个这样的课程 public class TypeATreeNodeInitializer { public TypeATreeNode initialize(){ return getTypeATree(); } private TypeATreeNode getTyp

我试图理解JVM和热点优化器的内部结构

我尽可能快地处理初始化具有大量节点的对象树结构的问题。 现在,对于给定的每个树结构,我们生成Java源代码来初始化树,如下所示。最后,我们有数千个这样的课程

public class TypeATreeNodeInitializer {

    public TypeATreeNode initialize(){
        return getTypeATree();

    }

    private TypeATreeNode getTypeATree() {
        TypeATreeNode node = StaticTypeAFactory.create();

        TypeBTreeNode child1 = getTypeBTreeNode1(); 
        node.getChildren().add(child1);

        TypeBTreeNode child2 = getTypeBTreeNode2(); 
        node.getChildren().add(child2);

        //... may be many more children

        return node;
    }

    private TypeBTreeNode getTypeBTreeNode1() {
        TypeBTreeNode node = StaticTypeBFactory.create();

        TypeBTreeNode child1 = getTypeCTreeNode1(); 
        node.getChildren().add(child1);

        //store of value in variable first
        String value1 = "Some value";
        // assign value to node
        node.setSomeValue(value1);

        boolean value2 = false;
        node.setSomeBooleanValue(value2);


        return node;
    }



    private TypeBTreeNode getTypeCTreeNode1() {
        // ...
        return null;
    }

    private TypeBTreeNode getTypeBTreeNode2() {
        // ...
        return null;
    }

    //...  many more child node getter / initializer
}
如您所见,要分配给树节点的值首先存储在局部变量中。查看生成的字节码,结果是:

  • 将变量从常量池加载到堆栈//例如字符串“Some Value”

  • 在局部变量中存储变量

  • 从方法目标加载到堆栈//例如TypeBTreeNode

  • 从局部变量/“某些值”加载变量

  • setter的调用

  • 但是,通过不存储到局部变量并直接传递参数,可以缩短编写时间。因此,它变成了:

  • 将方法目标推送到堆栈//例如TypeBTreeNode

  • 然后将常量加载到堆栈//“Some Value”

  • 然后调用setter

  • 我知道在其他语言(例如C++)中,编译器能够进行这样的优化

    在Java中,热点优化器负责在运行时实现这种神奇功能。
    然而,据我对文档的理解,HotSpot只在第500次方法调用(客户机VM)之后才生效

    问题:

    • 我是否理解正确:如果我只对每个树初始化一次,但对大量(比如说10.000)生成的树初始化器执行初始化,则会对每个树初始化器执行第一个字节码序列,因为它们是具有不同方法的不同类,每个方法只调用一次

    • 我怀疑不使用局部变量重写genreator会大大加快速度,因为我节省了大约三分之一的字节码指令和可能昂贵的变量负载。我知道,如果不进行测量,很难判断这一点,但是修改生成器代码是非常重要的,所以您认为值得一试吗


      • 删除这样的临时/堆栈变量几乎总是过早优化。你的处理器每秒可以处理数亿条这样的指令;同时,如果您正在初始化数以万计的任何东西,您的程序可能会在某个时刻阻塞,等待内存分配


        我的建议是,在对代码进行概要分析之前,不要进行优化。同时,编写尽可能容易阅读的代码,这样当您确实需要返回并修改某些内容时,就很容易找到需要更新的地方。

        优化俱乐部的第一条规则是“不要优化”。也就是说

        只为局部(堆栈)变量指定一个值以引用它一次已经没有意义了。如果我正在查看这段代码,我会让作者删除赋值,然后将
        get…()
        的结果传递到
        add()


        这不是一个“过早优化”,而是一个代码简化(代码质量)问题。由于JIT编译器将在运行时优化代码,因此消除一些字节码这一事实通常也不需要考虑。在这种情况下,由于这些初始值设定项听起来好像只运行一次,因此可能永远不会达到此优化的阈值,因此消除不必要的堆栈分配和加载是有价值的。

        在优化之前,JVM会逐字节运行代码并分析其行为。基于此观察,它将把您的代码编译成机器代码。因此,很难就此给出一般性建议。但是,您应该只将字节码视为一般抽象,而不是性能基础

        一些经验法则:

      • 避免使用大型方法,因为这些方法通常不会内联到其他方法中,即使JVM认为这是个好主意。这是为了避免内存开销,因为内联大型方法会创建大量重复代码
      • 尽可能避免多态性和不稳定分支。如果您的VM发现方法调用只命中特定类,这是个好消息。JVM很可能会删除此调用的虚拟属性。类似地,稳定的分支可以帮助您进行分支预测
      • 避免为长寿命对象分配对象。如果你创造了很多东西,让它们年轻的死去,然后让它们长时间的存在

      • 这些方法看起来很简单。为什么不尝试创建一个单一的通用解决方案?这可能也会节省大量的类加载时间。这个类只是示例性的。在实际应用中,非专家用户使用DSL编写应用程序逻辑。这样,他们就可以创建全新的节点类型,为新字段使用不同的setter。我可能会错过一些东西,但我认为用一个通用的解决方案是无法实现的。嗯,从远处看很难说。难道你不能将用户类型包装在节点中,而不是用户直接定义节点类型吗?你是说,用户将定义数千种不同的节点类型?听起来不是很有说服力。除此之外,如果初始化只发生一次,那么您肯定看到了错误的结果。用户将在这些节点初始化后对其进行处理,不是吗?还有你对“不用本地人就可以大大加快重写生成器”的怀疑,不,那是不会发生的…