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

Pio*_*ler 6 java debugging performance jit classloader

我正在寻找一种方式来提供最快的(我的意思是零时间 -编译/类加载/ JIT时间分辨)可以开/关标志if条件.当然,每次应用程序运行时,此条件只会更改一次 - 启动时.

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

我可以将条件移动到单独的.jar类和带条件的方法分开,在那里我生成两个版本.jar并在应用程序启动时在类路径中打开这些版本?将JIT删除调用方法在不同的.jar ,如果它发现,该方法是空的

我可以通过在类路径中实现"ClassWithMyCondition"提供两个类来实现,其中一个类将具有真正的实现,第二个将只有空方法并实例化其中一个Class.forName.newInstance()?将JIT从我的主要删除对空方法的调用非常循环嵌套的方法?

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

rol*_*lfl 11

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

这样做的优点是每个实现都是互斥的,JIT编译器之类的东西可以忽略这个特定运行的所有无用代码.

  • 干?不,想想像java.util.List这样的东西......而不是一个在每个方法中都有条件的类来说`if(链接){do linked list things} else {do array-list things}`你改为`List`,`ArrayList`和`LinkedList`的两个实现,你选择你想要的那个,并且不需要`if`. (4认同)

ysh*_*vit 7

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

只要把final static boolean不是一个编译时间常数(如JLS中定义)的地方,并不管你想要的"条件"的编写引用它.JVM将在第一次看到它时对其进行评估,并且当代码获得JIT时,JVM将知道该值不会更改,然后可以删除检查,如果值为false,则删除块.

一些消息来源:Oracle有一个关于性能技术的wiki页面,它说尽可能使用常量(请注意,在这种情况下,编译器是JVM/JIT,因此final即使它不是编译器,字段也算作常量 -时间常数由JLS标准).该页面链接到JIT采用的性能策略索引,其中提到了诸如常量折叠和流敏感重写等技术,包括死代码删除.


Eri*_*zke 3

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

final static boolean customProp = "true".equalsIgnoreCase(System.getProperty("customProp"));
Run Code Online (Sandbox Code Playgroud)

根据您的命令行参数,该static final值会发生变化。这会将值设置为true

java -DcustomProp="true" -jar app.jar
Run Code Online (Sandbox Code Playgroud)

虽然这会将值设置为false

java -jar app.jar
Run Code Online (Sandbox Code Playgroud)

这给您带来了 a 的好处static final boolean,但允许在不重新编译的情况下更改值。


[编辑]

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