Java最终布尔优化
请考虑以下设置:Java最终布尔优化,java,optimization,Java,Optimization,请考虑以下设置: // debugger class public class Debug { // setting public final static boolean DEBUG = false; void print_checked( String s ) { if( DEBUG ) System.out.print( s ); } void print_unchecked( String s )
// debugger class
public class Debug
{
// setting
public final static boolean DEBUG = false;
void print_checked( String s )
{
if( DEBUG )
System.out.print( s );
}
void print_unchecked( String s )
{
System.out.print( s );
}
}
// worker class
public class Algorithm
{
Debug debugger;
public void heavyWeightAlgorithmImplementation()
{
// method 1
debugger.print_checked( "This method 1" );
// method 2
if( debugger.DEBUG )
debugger.print_unchecked( "Or this method 2" );
}
}
我读到Java中的final boolean
s很可能会被优化掉。但是,正如在我的设置中一样,if条件位于另一个类中,并且当前在print\u checked()
中实现。Java是否也优化了函数调用(方法1),还是必须像方法2那样重写所有内容
编辑#1:再次添加静态Java会随着时间的推移而变化,它会变得更加复杂。所以把这个和一撮盐一起吃 在javac编译期间,如果编译器能够证明某段代码永远不会被访问,那么它将被删除 在运行时,现代Oracle JVM倾向于以解释模式运行字节码,在这种情况下,它将进行检查,直到JVM认为代码“热”到可以优化为止。此时,热点开始出现,它正朝着这样一种观点发展,即场将被假定为最终场,直到它证明不是最终场。此时,它将尝试预测分支,并相当积极地内联代码 但是,如果我回忆起,非静态字段的最终keword不能被运行时视为优化的最终keword,因为有方法在运行时更改这些字段的值。一种对JVM内部成员的憎恨
因此,出于您的选择,我推荐方法1,因为它减少了块需要复制的位置数量。但是,如果可能的话,我会将DEBUG字段设置为静态,这样可以更可靠地删除if语句。在您的示例中,第一种方法更好。但是,如果在调试时需要一些串联操作,则第二个变量更可取 以下是一个例子:
if( debugger.DEBUG )
debugger.print_unchecked( "Or this method 2" + oldValue + "//" + newValue);
在这种情况下,编译器可以避免不必要的字符串连接和调用toString()方法
这是我的测试:
public class DebuggerTest {
static final int ITER_NUM = 5000000;
public static class Debug
{
// setting
public final static boolean DEBUG = false;
private final List<String> collector = new ArrayList<String>(ITER_NUM);
void print_checked( String s )
{
if( DEBUG )
collector.add(s);
}
void print_unchecked( String s )
{
collector.add(s);
}
}
public static void main(String[] args) {
Debug debug = new Debug();
long time = System.currentTimeMillis();
for (int i = 0; i < ITER_NUM; i++) {
debug.print_checked("Debug message " + i);
}
System.out.println("First: " + (System.currentTimeMillis() - time));
debug = new Debug();
time = System.currentTimeMillis();
for (int i = 0; i < ITER_NUM; i++) {
if (Debug.DEBUG)
debug.print_unchecked("Debug message " + i);
}
System.out.println("Second: " + (System.currentTimeMillis() - time));
}
}
我用jdk1.7编译了上面的示例,并在JDGUI中打开了*.class文件。
示例:
class Debug
{
// setting
public static final boolean DEBUG = false;
void print_checked( String s )
{
if( DEBUG )
System.out.print( s );
}
void print_unchecked( String s )
{
System.out.print( s );
}
}
public class Main
{
public static void main(String[] argc)
{
Debug debugger = new Debug();
debugger.print_checked(" This method 1");
if (debugger.DEBUG)
debugger.print_unchecked( "Or this method 2");
}
}
京东图形用户界面:
// Debug.class
import java.io.PrintStream;
class Debug
{
public static final boolean DEBUG = false;
void print_checked(String paramString) {
}
void print_unchecked(String paramString) {
System.out.print(paramString);
}
}
// Main.class
public class Main
{
public static void main(String[] paramArrayOfString)
{
Debug localDebug = new Debug();
localDebug.print_checked(" This method 1");
}
}
如您所见,“print\u checked”方法保留在Main.class代码中,但“print\u unchecked”被删除。我不确定,但我认为空方法“print_checked”也可能被Oracle JVM忽略。我非常确定该方法将被内联,因此使用方法2将一事无成。您是否尝试过这两种方法以查看是否有任何可测量的差异?如果此代码不是非常耗时的,只需使用更易于维护的版本即可。您可能会节省0.000000000001秒。如果重复数十亿次,1ns的差异将变得显著。它将被优化。Java可以看到if语句真正读取
if(false)
,并将删除整个代码块。我会在JLSOh中寻找位置,好吧,我的错。误解了C++的const
和Java的final
的区别。现在将添加static
。设置静态最终布尔值的一个好技巧是推断提供给JVM的-ea标志的值。通过这种方式,您可以关闭调试并从执行代码中剥离,直到您想要打开它,然后在不重新编译的情况下打开它。请参阅以获取如何执行此操作的示例。感谢您提供jd gui提示
// Debug.class
import java.io.PrintStream;
class Debug
{
public static final boolean DEBUG = false;
void print_checked(String paramString) {
}
void print_unchecked(String paramString) {
System.out.print(paramString);
}
}
// Main.class
public class Main
{
public static void main(String[] paramArrayOfString)
{
Debug localDebug = new Debug();
localDebug.print_checked(" This method 1");
}
}