问题描述
我的过程很漫长,有两个主要阶段。 第一阶段和第二阶段的执行路径略有不同。
我刚刚意识到,如果我用不同的名称创建相同方法的副本,并在每个阶段使用不同的名称,那么根据JMH( -server
,在java-7-openjdk-amd64
),我可以得到25%以上的加速该方法在第二阶段进行调用(超过5次调用预热后,以5次调用衡量的方法调用数百万次)。
有没有办法告诉JVM忘记关于方法的先前优化并从头开始重新学习?
在以下示例代码中, run
了基准测试方法, checkChar0
在stage2
调用checkChar
和checkChar0
两个版本之间进行了比较。
final public void run(){
sumStg1=0;
for(int i=0; i< 10000; i++){
String str = consumeString();
for(int i= 0; i<K; i++){
sumStg1 += checkChar(str.charAt(i), i)?1:0;
}
}
sumStg2=0;
for(int j=0; j< 10000000; j++){
String str = consumeString();
for(int i=K/2; i<str.length(); i++){
sumStg2 += checkChar(str.charAt(i), i)?1:0;
}
}
}
final public boolean checkChar(char in, int i){
if(i < K/2){
...
} else if (i < K){
...
} else {
...
}
}
//identical method to checkChar
final public boolean checkChar0(char in, int i){
if(i < K/2){
...
} else if (i < K){
...
} else {
...
}
}
1楼
我想到两个想法:
A)通过调用该方法,并使用指向该方法的新方法句柄对其进行更新,然后调用应该触发调用方法的重新编译。
提供类似的功能。
我不知道的是,JVM是否可以在此处应用任何技巧,如果方法被自身替换,则跳过重新编译。
B)应用一个类文件重新 ,该本质上不会改变任何东西,除了可能将一些惰性字节码附加到方法主体或其他任何东西上。
请注意,我还没有尝试过任何方法,因此无法保证。
您也可能没有基准测试基准。 JMH并不是魔术棒,只需挥舞代码即可消除所有测量问题。
您说您的实际应用程序包含两个阶段,并且只有一个阶段过渡。
但是在JMH中,您总体上使用了10个迭代(每个迭代有N个调用),这意味着随着新迭代的开始,将进行10 * N个正向相位转换和10 * N个反向转换。 这最终将导致JIT放弃重新编译。
JMH旨在在您的应用程序依赖一次性行为的情况下测量稳态性能。
2楼
另一个想法:
在新的类加载器中再次加载该类,并使用该版本而不是静态加载的版本。
为
-XX:CompileThreshold
设置更大的值。
(这两种方法都有明显的/明显的缺点,但是如果性能对您而言如此重要……)