Java JIT编译器会优化局部变量吗

Java JIT编译器会优化局部变量吗,java,jvm,Java,Jvm,Java JIT编译器是否会优化此代码: Class2 method() { Class foo = new Class(); Class2 bar = new Class2(); if (foo.variable == null) throw new RuntimeException(); bar.otherVariable = 5; return bar; } 通过这样做: Class2 method() {

Java JIT编译器是否会优化此代码:

Class2 method() {
     Class foo = new Class();
     Class2 bar = new Class2();

     if (foo.variable == null)
        throw new RuntimeException();

     bar.otherVariable = 5;
     return bar;
}
通过这样做:

Class2 method() {
     Class foo = new Class();

     if (foo.variable == null)
        throw new RuntimeException();

     Class2 bar = new Class2();
     bar.otherVariable = 5;

     return bar;
}

它是内存使用的优化。什么时候创建Class2并分配它的内存?

与大多数事情一样,答案是“视情况而定”

首先,Java编译器不会为您重新排序。字节码将按照您的布局

其次,当JIT被反复调用时,它将被调用。在经历多次(10000次)执行之前,它不会经历高级JIT编译

如果您反复调用此函数,并且字段始终以null形式传入,则它可能会优化函数以删除其余的代码,从而执行死代码消除和省略构造

另一方面,如果您拥有的类执行一些可见的副作用(例如,设置全局系统属性、创建线程、分配静态值),那么代码将不会被完全删除。它可以在线创建对象并有效地替换该构造函数


然而,可能值得注意的是,即使JIT没有对其进行优化,创建一个新实例然后立即可用于GC也是一个非常便宜的操作。分配是内存数组的一个凹凸指针,虽然可能会发生一些字段初始化,但它将位于缓存中几乎肯定很热的内存中,并占用很少的时间。当此方法返回时,类将符合GC的条件,并且可以被删除(假设没有终结器等)

为什么要依赖编译器?通常,最好的做法是自己编写优化的版本。第一个版本对我来说似乎更具可读性,我的意思是将所有变量放在开头,然后是所有语句。这两个片段并不等效,因为
Class2
构造函数可能会有副作用。因此,移动它可能会改变行为,因此JIT不会这样做(除非它真的很聪明)。在这种特定的情况下,可以假设在抛出
RuntimeException
时分配总是成功,并且构造函数总是运行,但这不仅要求构造函数没有副作用,而且也不可能抛出异常或错误感觉更干净,为什么不简单地使用
classfoo=newclass();二级钢筋;如果(foo.variable==null)抛出新的RuntimeException();bar=新类2();bar.otherVariable=5;返回杆。顺便说一下,说到干净的代码,
Class2
应该有一个合适的构造函数,而不是要求外部代码分配
otherVariable
。然后,代码看起来像
classfoo=newclass();如果(foo.variable==null)抛出新的RuntimeException();返回新类别2(5)
整个问题都解决了,所有变量都是在开始时懒散地构造的。
10000
执行只是一个神话,不会消失。C1不会优化对象的构造;您需要到达C2,这将是CompileThreshold(如果不使用分层编译)或Tier4CompileThreshold(如果使用分层编译)的最小值,而这些都是最小值,因为在此之后,代码将进入队列进行后续编译和安装,因此,您可以轻松地接到几百/千个电话。不知道为什么JVM会在编译日志中告诉您这是一个神话。