我很好奇在同一个匿名类中创建java8 lambda实例的性能。 (在win32 java build 1.8.0-ea-b106上执行测量)。我创建了一个非常简单的示例,并测量了java在创建lambda表达式时是否提出了new
运算符的一些优化:
static final int MEASURES = 1000000;
static interface ICallback{
void payload(int[] a);
}
/**
* force creation of anonymous class many times
*/
static void measureAnonymousClass(){
final int arr[] = {0};
for(int i = 0; i < MEASURES; ++i){
ICallback clb = new ICallback() {
@Override
public void payload(int[] a) {
a[0]++;
}
};
clb.payload(arr);
}
}
/**
* force creation of lambda many times
*/
static void measureLambda(){
final int arr[] = {0};
for(int i = 0; i < MEASURES; ++i){
ICallback clb = (a2) -> {
a2[0]++;
};
clb.payload(arr);
}
}
(完整的代码可以在那里:http://codepad.org/Iw0mkXhD)结果是可以预测的 - lambda赢了2次。
但实际上很少转变为closure显示lambda非常糟糕的时间。匿名课程赢了10次! 所以现在匿名类看起来像:
ICallback clb = new ICallback() {
@Override
public void payload() {
arr[0]++;
}
};
lambda的确如下:
ICallback clb = () -> {
arr[0]++;
};
(完整代码可以在那里:http://codepad.org/XYd9Umty) 任何人都可以解释一下为什么在处理闭包时存在如此大(差)的差异?
答案 0 :(得分:26)
一些评论想知道我的底部基准是否存在缺陷 - 在引入大量随机性(以防止JIT优化太多东西)之后,我仍然得到类似的结果,所以我倾向于认为它没问题。
与此同时,lambda实施团队遇到了this presentation。第16页显示了一些性能数据:内部类和闭包具有相似的性能/非捕获lambda的速度提高了5倍。
并且@StuartMarks发布了这个very interesting link来解析lambda性能。底线是JIT后编译,lambdas和匿名类在当前的Hostpot JVM实现上执行类似的操作。
我发布了你的测试。问题是第一种方法运行时间仅为20 ms,第二种方法运行时间仅为2 ms。虽然这是10:1的比例,但它没有代表性,因为测量时间太小。
然后我修改了你的测试以允许更多的JIT热身,我得到与jmh类似的结果(即匿名类和lambda之间没有区别)。
public class Main {
static interface ICallback {
void payload();
}
static void measureAnonymousClass() {
final int arr[] = {0};
ICallback clb = new ICallback() {
@Override
public void payload() {
arr[0]++;
}
};
clb.payload();
}
static void measureLambda() {
final int arr[] = {0};
ICallback clb = () -> {
arr[0]++;
};
clb.payload();
}
static void runTimed(String message, Runnable act) {
long start = System.nanoTime();
for (int i = 0; i < 10_000_000; i++) {
act.run();
}
long end = System.nanoTime();
System.out.println(message + ":" + (end - start));
}
public static void main(String[] args) {
runTimed("as lambdas", Main::measureLambda);
runTimed("anonymous class", Main::measureAnonymousClass);
runTimed("as lambdas", Main::measureLambda);
runTimed("anonymous class", Main::measureAnonymousClass);
runTimed("as lambdas", Main::measureLambda);
runTimed("anonymous class", Main::measureAnonymousClass);
runTimed("as lambdas", Main::measureLambda);
runTimed("anonymous class", Main::measureAnonymousClass);
}
}
两种方法的最后一次运行大约需要28秒。
我已经运行the same test with jmh,底线是这四种方法花费的时间与等效方法相同:
void baseline() {
arr[0]++;
}
换句话说,JIT内联匿名类和lambda,它们完全相同。
结果摘要:
Benchmark Mean Mean error Units
empty_method 1.104 0.043 nsec/op
baseline 2.105 0.038 nsec/op
anonymousWithArgs 2.107 0.028 nsec/op
anonymousWithoutArgs 2.120 0.044 nsec/op
lambdaWithArgs 2.116 0.027 nsec/op
lambdaWithoutArgs 2.103 0.017 nsec/op