Java JIT编译器优化:使用相同参数的第二个方法调用
假设我有一个用于验证特定值的方法,例如,一个方法Java JIT编译器优化:使用相同参数的第二个方法调用,java,validation,optimization,parameters,jit,Java,Validation,Optimization,Parameters,Jit,假设我有一个用于验证特定值的方法,例如,一个方法isEven: public static boolean isEven(int evenSize) { return evenSize % 2 == 0; } 我使用此方法验证外部输入(例如来自磁盘或用户)。但在此之后,我也在需要偶数值的方法中使用此方法: public static String padToEven(int evenSize, String string) { if (!isEven(evenSize)) {
isEven
:
public static boolean isEven(int evenSize) {
return evenSize % 2 == 0;
}
我使用此方法验证外部输入(例如来自磁盘或用户)。但在此之后,我也在需要偶数值的方法中使用此方法:
public static String padToEven(int evenSize, String string) {
if (!isEven(evenSize)) { // <-- duplication of isEven method
throw new IllegalArgumentException("evenSize argument is not even");
}
if (string.length() >= evenSize) {
return string;
}
StringBuilder sb = new StringBuilder(evenSize);
sb.append(string);
for (int i = string.length(); i < evenSize; i++) {
sb.append('x');
}
return sb.toString();
}
publicstaticstringpadtoeven(int-evenSize,stringstring){
如果(!isEven(evenSize)){/=evenSize){
返回字符串;
}
StringBuilder sb=新StringBuilder(均匀尺寸);
某人附加(字符串);
for(int i=string.length();i
因此,基本上我们向padToEven()
提供已经验证过的参数,并使用相同的isEven
函数验证参数。JIT编译器(比如Java版本8)是否可能找到第二个调用并对其进行优化
您可以假设检查不依赖于动态值(即,它对提供的参数值具有确定性)。除了返回值(如日志语句)之外,它也没有任何副作用。我认为Java根本不会进行任何过程间分析。但是,该方法有一些内联的可能性。当您内联所有内容时,则
if (evenSize % 2 != 0) {
throw new IllegalArgumentException("evenSize argument is not even");
}
... some code not changing evenSize
if (evenSize % 2 != 0) {
throw new IllegalArgumentException("evenSize argument is not even");
}
这对于优化来说是非常琐碎的。这个内联不是你可以依赖的,因为有一个内联限制很快就会达到
其他优化
OTOH,测试非常简单,可能会优化到
public static boolean isEven(int evenSize) {
return (evenSize & 1) == 0;
}
它使用了更快的操作。但这不是我所关心的(因为有很多其他的代码,所以你不能获得太多)
我想,最好的优化应该是取消
StringBuilder
。什么???是的,说真的,char[]
可以:
char[] result = new char[evenSize];
for (int i = 0; i < string.length(); i++) {
result[i] = string.charAt(i);
}
for (int i = string.length(); i < evenSize; i++) {
result[i] = 'x';
}
return new String(result);
char[]result=新字符[evenSize];
对于(int i=0;i
不久前,我做了一些测量,显示它应该快得多。这可能已经随着最近的JIT而改变。而不是重要的部分:
什么样的优化在这里有意义?
没有,除非你
- 确实需要提高性能
- 对其进行分析并找到罪犯
- 准备花相当多的时间进行基准测试和分析
你上面的代码很好,不要碰它。显然,对于
我甚至是来说,这都无关紧要,但例如isPrime
操作上的差异可能会很明显,尤其是在循环中使用时。有趣的问题!我怀疑,在一般情况下,这是否有可能安全地确定这种重用。@boristeshider是的,可以非常棘手。JIT编译器有很多未知因素(副作用,状态)调用之间可能也有很多字节码。这取决于你没有提到的一些事情,比如该值是如何进入该函数的,以及这些时刻之间控制流的形状。例如,如果padToEven
作为已选中的isEven
函数的后代在某个地方被调用,这是很容易的更容易推理(但仍然是我不期望JVM进行的过程间分析级别)如果egmain
调用读取值的东西,检查它,将它放入某个静态字段,然后调用涉及padToEven
的其他东西,这还取决于谓词是否可以用数字抽象域表示。太好了,谢谢!请注意,isEven
方法只是泛型的一个示例c验证方法。我唯一要问的是重复那个方法调用。所以一切都到了“OTOH”是关于主题的。剩下的是关于代码其他部分的有趣讨论,这很好,但没有回答问题。所以基本上答案是:不会被优化,除非是内联的。@MaartenBodewes我知道写了太多的w.r.t.这个问题,但我按照我的想法做了,这可能是有用的。;)因为我通常也会给sec关于我的加密相关答案的urity建议我几乎不能抱怨:)我将答案分成3部分,而不是2部分,希望你不介意。当然,Java做“过程间分析”。这就是先进行内联,然后再进行所有其他优化的全部意义。因此,这只是命名问题。我怀疑手动处理char
数组是否有任何好处,即使是使用较旧的JVM也是如此。此外,当手动处理数组时,第一个循环没有理由重复调用charAt
应该比单个string.getChars(0,string.length(),result,0)调用更快…