Java中是否存在零时间启动(无重新编译)可切换条件标志?

时间:2013-10-24 19:15:49

标签: java performance debugging classloader jit

我正在寻找一种方法来为{提供最快(我的意思是零时间 - 编译/类加载/ JIT时间已解决)开/关标志 {1}}条件。当然,每次应用程序运行时,此条件只会更改一次 - 启动时。

我知道可以条件编译“条件编译时常量”,并且可以从代码中删除整个条件。但是,无需重新编译源代码的最快(也可能是简单)替代方案是什么?

我可以移动条件以单if与单一类别&有条件的方法,我生成.jar的两个版本,并在应用程序启动时在类路径中打开这些版本? JIT会在单独的.jar 中删除对方法的调用,如果它发现,该方法为空

我可以通过在实现“ClassWithMyCondition”的类路径中提供两个类来实现,其中一个类将具有真正的实现,第二个类将只有空方法并通过.jar和{{1实例化其中一个类JIT是否会从我的主要循环嵌套方法中删除对空方法的调用?

这个问题最简单的字节码操作解决方案是什么?

5 个答案:

答案 0 :(得分:11)

执行此类逻辑的标准方法是为所需功能创建接口,然后为该功能创建两个(或更多)实现。在您的运行时中只会加载其中一个实现,并且该实现可以进行所需的假设,以完全避免if条件。

这样做的好处是每个实现都是互斥的,像JIT编译器这样的东西可以忽略这个特定运行的所有无用代码。

答案 1 :(得分:7)

这里最简单的解决方案。不要为自己过度复杂化。

只需将不是final static boolean放在某处的编译时常量(如JLS中定义),并在任何需要“条件”编译的地方引用它。 JVM将在第一次看到它时对其进行评估,并且当代码获得JIT时,JVM将知道该值不会更改,然后可以删除检查,如果值为{{1} ,块。

一些消息来源:Oracle在performance techniques上有一个wiki页面,它表示在可能的情况下使用常量(请注意,在此上下文中,编译器是JVM / JIT,因此false字段计为一个常量,即使它不是JLS标准的编译时常量)。该页面链接到JIT采用的index of performance tactics,它提到了诸如常量折叠和流敏感重写等技术,包括删除死代码。

答案 2 :(得分:3)

您可以在命令行中传递自定义值,然后检查该值一次。所以在你的代码中,有这样的东西:

final static boolean customProp = "true".equalsIgnoreCase(System.getProperty("customProp"));

根据您的命令行参数,static final值将会更改。这会将值设置为true

java -DcustomProp="true" -jar app.jar

虽然这会将值设置为false

java -jar app.jar

这为您提供了static final boolean的好处,但允许在不重新编译的情况下更改值。


<强> [编辑]

如评论中所示,此方法不允许在编译时进行优化。 static final boolean的值在classload上设置,并且从那里保持不变。字节码的“正常”执行可能需要评估每if (customProp)。但是,JIT在运行时发生,将字节码编译为本机代码。此时,由于字节码具有运行时值,因此可以进行更积极的优化,例如内联或排除代码。请注意,您无法准确预测JIT是否或何时会启动。

答案 3 :(得分:1)

您应该从属性文件加载值,这样您就可以避免每次重新编译时都重新编译。只需更新文本文件,在下一个程序运行时,它就会使用新值。这是我很久以前写的一个例子:

https://github.com/SnakeDoc/JUtils/blob/master/src/net/snakedoc/jutils/Config.java

答案 4 :(得分:0)

每次运行时,JIT都会重新编译代码。无论你是否知道,你已经这样做了。这意味着如果你有一个JIT认为没有改变的字段(它甚至不必是最终的),它将被内联并且检查和代码被优化掉。

随着时间的推移,试图让智能JIT越来越难。