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而改变。而不是重要的部分:

什么样的优化在这里有意义? 没有,除非你

  • 确实需要提高性能
  • 对其进行分析并找到罪犯
  • 准备花相当多的时间进行基准测试和分析
不要这样做。幸运的是,JIT是针对使用短方法的干净代码进行优化的。它不能改进您的算法和数据结构,所以您可以在真正需要时进行优化。微优化的回报要少得多


你上面的代码很好,不要碰它。

显然,对于
我甚至是
来说,这都无关紧要,但例如
isPrime
操作上的差异可能会很明显,尤其是在循环中使用时。有趣的问题!我怀疑,在一般情况下,这是否有可能安全地确定这种重用。@boristeshider是的,可以非常棘手。JIT编译器有很多未知因素(副作用,状态)调用之间可能也有很多字节码。这取决于你没有提到的一些事情,比如该值是如何进入该函数的,以及这些时刻之间控制流的形状。例如,如果
padToEven
作为已选中的
isEven
函数的后代在某个地方被调用,这是很容易的更容易推理(但仍然是我不期望JVM进行的过程间分析级别)如果eg
main
调用读取值的东西,检查它,将它放入某个静态字段,然后调用涉及
padToEven
的其他东西,这还取决于谓词是否可以用数字抽象域表示。太好了,谢谢!请注意,
isEven
方法只是泛型的一个示例c验证方法。我唯一要问的是重复那个方法调用。所以一切都到了“OTOH”是关于主题的。剩下的是关于代码其他部分的有趣讨论,这很好,但没有回答问题。所以基本上答案是:不会被优化,除非是内联的。@MaartenBodewes我知道写了太多的w.r.t.这个问题,但我按照我的想法做了,这可能是有用的。;)因为我通常也会给sec关于我的加密相关答案的urity建议我几乎不能抱怨:)我将答案分成3部分,而不是2部分,希望你不介意。当然,Java做“过程间分析”。这就是先进行内联,然后再进行所有其他优化的全部意义。因此,这只是命名问题。我怀疑手动处理
char
数组是否有任何好处,即使是使用较旧的JVM也是如此。此外,当手动处理数组时,第一个循环没有理由重复调用
charAt
应该比单个
string.getChars(0,string.length(),result,0)调用更快…