Java JVM什么时候考虑字节码优化的代码?
我试图理解JVM和热点优化器的内部结构 我尽可能快地处理初始化具有大量节点的对象树结构的问题。 现在,对于给定的每个树结构,我们生成Java源代码来初始化树,如下所示。最后,我们有数千个这样的课程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
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
}
如您所见,要分配给树节点的值首先存储在局部变量中。查看生成的字节码,结果是:
然而,据我对文档的理解,HotSpot只在第500次方法调用(客户机VM)之后才生效 问题:
- 我是否理解正确:如果我只对每个树初始化一次,但对大量(比如说10.000)生成的树初始化器执行初始化,则会对每个树初始化器执行第一个字节码序列,因为它们是具有不同方法的不同类,每个方法只调用一次
- 我怀疑不使用局部变量重写genreator会大大加快速度,因为我节省了大约三分之一的字节码指令和可能昂贵的变量负载。我知道,如果不进行测量,很难判断这一点,但是修改生成器代码是非常重要的,所以您认为值得一试吗
- 删除这样的临时/堆栈变量几乎总是过早优化。你的处理器每秒可以处理数亿条这样的指令;同时,如果您正在初始化数以万计的任何东西,您的程序可能会在某个时刻阻塞,等待内存分配
我的建议是,在对代码进行概要分析之前,不要进行优化。同时,编写尽可能容易阅读的代码,这样当您确实需要返回并修改某些内容时,就很容易找到需要更新的地方。优化俱乐部的第一条规则是“不要优化”。也就是说 只为局部(堆栈)变量指定一个值以引用它一次已经没有意义了。如果我正在查看这段代码,我会让作者删除赋值,然后将
get…()
的结果传递到add()
这不是一个“过早优化”,而是一个代码简化(代码质量)问题。由于JIT编译器将在运行时优化代码,因此消除一些字节码这一事实通常也不需要考虑。在这种情况下,由于这些初始值设定项听起来好像只运行一次,因此可能永远不会达到此优化的阈值,因此消除不必要的堆栈分配和加载是有价值的。在优化之前,JVM会逐字节运行代码并分析其行为。基于此观察,它将把您的代码编译成机器代码。因此,很难就此给出一般性建议。但是,您应该只将字节码视为一般抽象,而不是性能基础 一些经验法则:
这些方法看起来很简单。为什么不尝试创建一个单一的通用解决方案?这可能也会节省大量的类加载时间。这个类只是示例性的。在实际应用中,非专家用户使用DSL编写应用程序逻辑。这样,他们就可以创建全新的节点类型,为新字段使用不同的setter。我可能会错过一些东西,但我认为用一个通用的解决方案是无法实现的。嗯,从远处看很难说。难道你不能将用户类型包装在节点中,而不是用户直接定义节点类型吗?你是说,用户将定义数千种不同的节点类型?听起来不是很有说服力。除此之外,如果初始化只发生一次,那么您肯定看到了错误的结果。用户将在这些节点初始化后对其进行处理,不是吗?还有你对“不用本地人就可以大大加快重写生成器”的怀疑,不,那是不会发生的…