我有这段代码在做Range Minimum
Query
。当t =
100000时,i和j始终在每条输入行中更改,因此在Java 8u60中其执行时间约为12秒。
for (int a0 = 0; a0 < t; a0++) {
String line = reader.readLine();
String[] ls = line.split(" ");
int i = Integer.parseInt(ls[0]);
int j = Integer.parseInt(ls[1]);
int min = width[i];
for (int k = i + 1; k <= j; k++) {
if (min > width[k]) {
min = width[k];
}
}
writer.write(min + "");
writer.newLine();
}
当我提取一个新方法以找到最小值时,执行时间快了4倍(约2.5秒)。
for (int a0 = 0; a0 < t; a0++) {
String line = reader.readLine();
String[] ls = line.split(" ");
int i = Integer.parseInt(ls[0]);
int j = Integer.parseInt(ls[1]);
int min = getMin(i, j);
writer.write(min + "");
writer.newLine();
}
private int getMin(int i, int j) {
int min = width[i];
for (int k = i + 1; k <= j; k++) {
if (min > width[k]) {
min = width[k];
}
}
return min;
}
我一直认为方法调用很慢。但是这个例子却相反。Java 6也演示了这一点,但是在两种情况下(17秒和10秒)执行时间都慢得多。有人可以对此提供一些见识吗?
TL; DR JIT编译器在第二种情况下有更多机会优化内部循环,因为堆栈替换发生在不同的位置。
我设法通过减少测试用例重现了问题。 不涉及I / O或字符串操作,仅涉及两个具有数组访问权限的嵌套循环。
public class NestedLoop {
private static final int ARRAY_SIZE = 5000;
private static final int ITERATIONS = 1000000;
private int[] width = new java.util.Random(0).ints(ARRAY_SIZE).toArray();
public long inline() {
long sum = 0;
for (int i = 0; i < ITERATIONS; i++) {
int min = width[0];
for (int k = 1; k < ARRAY_SIZE; k++) {
if (min > width[k]) {
min = width[k];
}
}
sum += min;
}
return sum;
}
public long methodCall() {
long sum = 0;
for (int i = 0; i < ITERATIONS; i++) {
int min = getMin();
sum += min;
}
return sum;
}
private int getMin() {
int min = width[0];
for (int k = 1; k < ARRAY_SIZE; k++) {
if (min > width[k]) {
min = width[k];
}
}
return min;
}
public static void main(String[] args) {
long startTime = System.nanoTime();
long sum = new NestedLoop().inline(); // or .methodCall();
long endTime = System.nanoTime();
long ms = (endTime - startTime) / 1000000;
System.out.println("sum = " + sum + ", time = " + ms + " ms");
}
}
inline
变体的确比慢3-4倍methodCall
。
我使用以下JVM选项来确认两个基准测试均 在最高层上 进行 编译,
并且在两种情况下均成功进行了[OSR(堆栈上替换)](http://codingdict.com/questions/119224。
-XX:-TieredCompilation
-XX:CompileOnly=NestedLoop
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintCompilation
-XX:+TraceNMethodInstalls
251 46 % NestedLoop::inline @ 21 (70 bytes)
Installing osr method (4) NestedLoop.inline()J @ 21
271 46 NestedLoop::getMin (41 bytes)
Installing method (4) NestedLoop.getMin()I
274 47 % NestedLoop::getMin @ 9 (41 bytes)
Installing osr method (4) NestedLoop.getMin()I @ 9
314 48 % NestedLoop::methodCall @ 4 (30 bytes)
Installing osr method (4) NestedLoop.methodCall()J @ 4
这意味着JIT可以完成其工作,但是生成的代码必须不同。
让我们用进行分析-XX:+PrintAssembly
。
0x0000000002df4dd0: inc %ebp ; OopMap{r11=Derived_oop_rbx rbx=Oop off=114}
;*goto
; - NestedLoop::inline@53 (line 12)
0x0000000002df4dd2: test %eax,-0x1d64dd8(%rip) # 0x0000000001090000
;*iload
; - NestedLoop::inline@21 (line 12)
; {poll}
0x0000000002df4dd8: cmp $0x1388,%ebp
0x0000000002df4dde: jge 0x0000000002df4dfd ;*if_icmpge
; - NestedLoop::inline@26 (line 12)
0x0000000002df4de0: test %rbx,%rbx
0x0000000002df4de3: je 0x0000000002df4e4c
0x0000000002df4de5: mov (%r11),%r10d ;*getfield width
; - NestedLoop::inline@32 (line 13)
0x0000000002df4de8: mov 0xc(%r10),%r9d ; implicit exception
0x0000000002df4dec: cmp %r9d,%ebp
0x0000000002df4def: jae 0x0000000002df4e59
0x0000000002df4df1: mov 0x10(%r10,%rbp,4),%r8d ;*iaload
; - NestedLoop::inline@37 (line 13)
0x0000000002df4df6: cmp %r8d,%r13d
0x0000000002df4df9: jg 0x0000000002df4dc6 ;*if_icmple
; - NestedLoop::inline@38 (line 13)
0x0000000002df4dfb: jmp 0x0000000002df4dd0
0x0000000002da2af0: add $0x8,%edx ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2af3: cmp $0x1381,%edx
0x0000000002da2af9: jge 0x0000000002da2b70 ;*iload_1
; - NestedLoop::getMin@16 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2afb: mov 0x10(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b00: cmp %r11d,%ecx
0x0000000002da2b03: jg 0x0000000002da2b6b ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b05: mov 0x14(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b0a: cmp %r11d,%ecx
0x0000000002da2b0d: jg 0x0000000002da2b5c ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b0f: mov 0x18(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b14: cmp %r11d,%ecx
0x0000000002da2b17: jg 0x0000000002da2b4d ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b19: mov 0x1c(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b1e: cmp %r11d,%ecx
0x0000000002da2b21: jg 0x0000000002da2b66 ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b23: mov 0x20(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b28: cmp %r11d,%ecx
0x0000000002da2b2b: jg 0x0000000002da2b61 ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b2d: mov 0x24(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b32: cmp %r11d,%ecx
0x0000000002da2b35: jg 0x0000000002da2b52 ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b37: mov 0x28(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b3c: cmp %r11d,%ecx
0x0000000002da2b3f: jg 0x0000000002da2b57 ;*iinc
; - NestedLoop::getMin@33 (line 36)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b41: mov 0x2c(%r9,%rdx,4),%r11d ;*iaload
; - NestedLoop::getMin@22 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b46: cmp %r11d,%ecx
0x0000000002da2b49: jg 0x0000000002da2ae6 ;*if_icmple
; - NestedLoop::getMin@23 (line 37)
; - NestedLoop::methodCall@11 (line 27)
0x0000000002da2b4b: jmp 0x0000000002da2af0
编译后的代码完全不同。methodCall
优化效果更好。
width
字段被缓存在寄存器中。相反,inline
变体
width
每次从内存中加载数组;OSR编译的方法并非总是能很好地进行优化,因为它们必须在过渡点保持已解释堆栈帧的状态。这是相同问题的另一个示例。
堆栈上替换通常发生在向后分支(即循环的底部)。inline
方法具有两个嵌套循环,OSR发生在内循环内部,而OSR发生methodCall
一个外循环。OSR在外循环中的过渡更有利,因为JIT编译器具有更大的自由来优化内循环。而这正是您的情况。
问题内容: 我有这段代码在做Range Minimum Query 。当t = 100000时,i和j始终在每条输入行中更改,因此在Java 8u60中其执行时间约为12秒。 当我提取一个新方法以找到最小值时,执行时间快了4倍(约2.5秒)。 我一直认为方法调用很慢。但是这个例子却相反。Java 6也演示了这一点,但是在两种情况下(17秒和10秒)执行时间都慢得多。有人可以对此提供一些见识吗? 问
本文向大家介绍Java调用方法,包括了Java调用方法的使用技巧和注意事项,需要的朋友参考一下 示例 使用反射,可以在运行时调用对象的方法。 该示例显示了如何调用String对象的方法。
我的问题是关于JMeter和BeanShell后处理程序。 我已经用Eclipse开发了一个Java项目,并将该项目导出到一个JAR中。我已经把这个jar放在JMeter的/lib/ext文件夹中。 我不明白为什么当我直接调用jar时它会工作,为什么当我用JMeter做同样的事情时它不会工作。 谢谢你的帮助。
有人能告诉我用两种不同的方法调用同一个函数的区别,以及编译器在这两种情况下到底做了什么;比如:
问题内容: 我对是否应该手动内联一些性能敏感算法中称为100k-1百万次的小型方法感兴趣。 首先,我认为通过不进行内联会产生一些开销,因为JVM必须确定是否内联此方法(甚至不能这样做)。 但是,前几天,我用静态方法调用替换了此手动内联代码,并发现性能得到了提高。那怎么可能?这是否表明实际上没有任何开销,而让JVM按其“意愿”内联实际上可以提高性能?还是这在很大程度上取决于平台/架构? (发生性能提
本文向大家介绍汇总java调用python方法,包括了汇总java调用python方法的使用技巧和注意事项,需要的朋友参考一下 本文为大家分享了java调用python方法,供大家参考,具体内容如下 一、在java类中直接执行python语句 调用的结果是Tue,在控制台显示出来,这是直接进行调用的。 二、在java中调用本机python脚本中的函数 首先建立一个python脚本,名字为:my_u