如果我们使用Dynamic Invoke
,应用程序是否有任何性能改进?如果不是它的优势是什么?
答案 0 :(得分:6)
所以最后的答案是:
使用callites调用动态比传统方法调用更快。
对于字段访问来说,唯一更快的是直接访问字段而不使用任何方法调用并使用不安全的。
答案是没有调用动态不慢。它很快。它非常快。
较新的更新:
另一次更新(周日晚些时候) 我更改了代码以使用callsite进行动态调用,这改变了时间。
(所有运行JDK 1.8 build 94)
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b94)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b36, mixed mode)
1,000次
description duration in nanoseconds
regular method call time 2095
invoke dynamic method call time 1098
reflection method call time 3104
field method invoke dynamic call time 1165
field method invoke reflection call time 689
unsafe field access time 94
direct field access (baseline) 92
10,000次
description duration in nanoseconds
regular method call time 68
invoke dynamic method call time 43
reflection method call time 202
field method invoke dynamic call time 42
field method invoke reflection call time 45
unsafe field access time 87
direct 86
100,000次
description duration in nanoseconds
regular method call time 70
invoke dynamic method call time 44
reflection method call time 249
field method invoke dynamic call time 45
field method invoke reflection call time 47
unsafe field access time 88
direct 36
1,000,000次
description duration in nanoseconds
regular method call time 11
invoke dynamic method call time 6
reflection method call time 12
field method invoke dynamic call time 6
field method invoke reflection call time 4
unsafe field access time 1
direct 0
10,000,000次
description duration in nanoseconds
regular method call time 9
invoke dynamic method call time 6
reflection method call time 25
field method invoke dynamic call time 6
field method invoke reflection call time 4
unsafe field access time 1
direct 0
100,000,000次
description duration in nanoseconds
regular method call time 9
invoke dynamic method call time 6
reflection method call time 12
field method invoke dynamic call time 6
field method invoke reflection call time 4
unsafe field access time 1
direct 0
更新了使用call-site并调用动态
的代码//fieldName is the reflection field (example below how to look it up and change its access)
MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName);
CallSite callSiteField = new ConstantCallSite(methodHandleFieldDirect);
methodHandleFieldDirect = callSiteField.dynamicInvoker();
name = (String) methodHandleFieldDirect.invokeExact(new Employee());
//Lookup invoke dynamic
methodType = MethodType.methodType(String.class);
methodHandle = lookup.findVirtual(Employee.class, "getName", methodType);
CallSite callSiteMethod = new ConstantCallSite(methodHandleFieldDirect);
methodHandle = callSiteMethod.dynamicInvoker();
要查看其余内容,您必须查看博客条目。有一些使用不安全,反射,调用,调用动态和其他的例子。 :)
Callsites对于加快调用动态非常重要。
http://rick-hightower.blogspot.com/2013/10/java-invoke-dynamic-examples-java-7.html
更新(旧版更新):
我拿出了hashCode和count代码,我添加了因为反射太快了以至于我认为循环完全以某种方式出现了JITTed:
已删除count / hashcode的1000万次运行employee.getName()与反射相比,性能有所提高但很复杂。这取决于您拨打电话的次数。您可能只关心代码是否处于紧密循环中。
我最近看到的基准测试显示比普通反射提高了15倍,而且比正常方式调用方法慢了2.5倍。但你知道那句老话,不要相信你所听到的,只读你所读的一半。
我想我会尝试一下。
我现在一直在使用反射和invokedynamic搞砸了。 看到 A short write up on invoke dynamic.
以下是我使用JDK 1.8 build 94获得的结果。
一百万次通话(结果以纳秒为单位):
10,000次通话
regular method call time = 103
invoke dynamic method call time = 116
reflection method call time = 252
100,000次通话(预热后)。
regular method call time = 46
invoke dynamic method call time = 112
reflection method call time = 171
1,000,000次来电
regular method call time = 23
invoke dynamic method call time = 35
reflection method call time = 30
反射在1M时比调用动态更快。嗯...奇怪。
10,000,000次通话
regular method call time = 34
invoke dynamic method call time = 24
reflection method call time = 43
现在调用dynamic比常规方法调用更快!
现在100,000,000
regular method call time = 22
invoke dynamic method call time = 24
reflection method call time = 28
此时,JIT编译器消除了所有的痛苦。 如果你不能再多花2到6纳秒,那么你需要有一些应对技巧。
以下是重新创建测试的代码(也按照上面的链接):
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class thisClass = lookup.lookupClass(); // (who am I?)
MethodType methodType;
MethodHandle methodHandle;
创建员工对象。
Employee employee = new Employee();
使用invoke dynamic查找getName(有关更多示例,请参阅博客,上面有链接)。
//Lookup invoke dynamic
methodType = MethodType.methodType(String.class);
methodHandle = lookup.findVirtual(Employee.class, "getName", methodType);
name = (String) methodHandle.invokeExact(new Employee());
System.out.println("invoke dynamic " + name);
使用反射查找Employee.getName。
//Lookup reflection
Method method = Employee.class.getMethod("getName", new Class<?>[]{});
name = (String) method.invoke(new Employee());
System.out.println("reflection " + name);
开始时间,结束时间,迭代次数(次数),计算时间,通常的嫌疑人。
long start = 0;
long end = 0;
long times = 100_000_000;
long regularTime;
long invokeDynamicTime;
long reflectionTime;
long count=0;
现在让我们为JVM做准备。
//warm up
for (int index =0 ; index < times; index++) {
employee.getName();
name = (String) methodHandle.invokeExact(employee);
name = (String) method.invoke(employee);
}
让我们计算常规方法调用。
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = employee.getName();
count += name.hashCode();
}
count=0;
end = System.nanoTime();
regularTime = end - start;
System.out.printf("regular method call time = %d\n", regularTime/times);
P.S。我添加了计数,所以我的代码不会以某种方式被删除。
现在让我们计算invokeDyanmic时间。
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) methodHandle.invokeExact(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
invokeDynamicTime = end - start;
System.out.printf("invoke dynamic method call time = %d\n", invokeDynamicTime/times);
现在让我们计算一下反射时间。
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) method.invoke(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
reflectionTime = end - start;
System.out.printf("reflection method call time = %d\n", reflectionTime/times);
我决定再添加一个。如果你真的只想要这个属性,那么如果你直接访问该字段会怎么样。
<强> 10,000 强>
regular method call time = 109
invoke dynamic method call time = 115
reflection method call time = 236
field method invoke dynamic call time = 178
field method reflection call time = 709
<强> 100_000 强>
regular method call time = 49
invoke dynamic method call time = 118
reflection method call time = 312
field method invoke dynamic call time = 75
field method reflection call time = 158
<强> 1_000_000 强>
regular method call time = 28
invoke dynamic method call time = 41
reflection method call time = 30
field method invoke dynamic call time = 11
field method reflection call time = 18
<强> 10_000_000 强>
regular method call time = 28
invoke dynamic method call time = 41
reflection method call time = 30
field method invoke dynamic call time = 11
field method reflection call time = 18
<强> 100_000_000 强>
regular method call time = 40
invoke dynamic method call time = 25
reflection method call time = 44
field method invoke dynamic call time = 10
field method reflection call time = 9
好的,这是字段访问的代码,比使用employee.getName()快4倍。
long start = 0;
long end = 0;
long times = 10_000_000;
long regularTime;
long invokeDynamicTime;
long reflectionTime;
long invokeDynamicTimeUsingField;
long fieldDirect;
long count=0;
//warm up
for (int index =0 ; index < times; index++) {
employee.getName();
name = (String) methodHandle.invokeExact(employee);
name = (String) method.invoke(employee);
name = (String) methodHandleFieldDirect.invokeExact(employee);
}
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = employee.getName();
count += name.hashCode();
}
count=0;
end = System.nanoTime();
regularTime = end - start;
System.out.printf(" regular method call time = %d\n", regularTime/times);
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) methodHandle.invokeExact(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
invokeDynamicTime = end - start;
System.out.printf(" invoke dynamic method call time = %d\n", invokeDynamicTime/times);
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) method.invoke(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
reflectionTime = end - start;
System.out.printf(" reflection method call time = %d\n", reflectionTime/times);
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) methodHandleFieldDirect.invokeExact(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
invokeDynamicTimeUsingField = end - start;
System.out.printf(" field method invoke dynamic call time = %d\n", invokeDynamicTimeUsingField/times);
//
start = System.nanoTime();
for (int index =0 ; index < times; index++) {
name = (String) fieldName.get(employee);
count += name.hashCode();
}
count=0;
end = System.nanoTime();
fieldDirect = end - start;
System.out.printf(" field method reflection call time = %d\n", fieldDirect/times);
}
现在实际的字段反射/调用动态代码:
Employee employee = new Employee();
fieldName = null;
for (Field field : Employee.class.getDeclaredFields()) {
if (field.getName().equals("name")) {
fieldName = field;
fieldName.setAccessible(true);
break;
}
}
MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName);
name = (String) methodHandleFieldDirect.invokeExact(new Employee());
System.out.println("method handle for field direct " + name);
//Lookup invoke dynamic
methodType = MethodType.methodType(String.class);
methodHandle = lookup.findVirtual(Employee.class, "getName", methodType);
name = (String) methodHandle.invokeExact(new Employee());
System.out.println("invoke dynamic " + name);
//Lookup reflection
Method method = Employee.class.getMethod("getName", new Class<?>[]{});
name = (String) method.invoke(new Employee());
System.out.println("reflection " + name);
答案 1 :(得分:1)
我认为OP意味着InvokeDynamic,如此处所提到的http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html用于方法调用。我从未使用过自己,但引用了this post looks very descriptive
“对于执行一些反射调用的库,性能差异可能无关紧要,特别是如果这些调用主要是为了在内存中动态设置一个静态结构来进行正常调用。但是在动态语言中,每个呼叫必须使用这些机制,这是一个严重的性能损失。“
答案 2 :(得分:0)
我认为你的意思是通过动态调用来反映。反射的成本比普通方法调用略高。
反射有许多用法,例如我广泛用于ui数据绑定..
答案 3 :(得分:0)
你可以参考这个链接。 http://www.infoq.com/news/2010/09/jdk7-slip 希望这会对你有所帮助