If we use Dynamic Invoke
, is there any performance improvement in the ap开发者_开发技巧plication? If not what is the its advantage?
So the final answer is this:
Invoke dynamic with callsites is faster than traditional method calls.
The only thing faster for field access is accessing the field directly without any method calls and using unsafe.
The answer is no invoke dynamic is not slow. It is fast. It is very fast.
Newer Update:
Another update (later that very Sunday) I changed the code to use a callsite for dynamic invoke and that changed the time quite a bit.
(All runs with 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 runs
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 runs
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 runs
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 runs
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 runs
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 runs
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
Updated code that uses call-site with invoke dynamic
//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();
To see the rest, you have to see the blog entry. There are examples of using unsafe, reflection, callsites, invoke dynamic and the rest. :)
Callsites are important for speeding up invoke dynamic.
http://rick-hightower.blogspot.com/2013/10/java-invoke-dynamic-examples-java-7.html
Update (older update):
I took out the hashCode and count code, which I added because reflection was so fast that I thought the loops were getting JITTed out altogether somehow:
10 million runs with count/hashcode removed employee.getName()- regular method call time = 25 nanoseconds
- invoke dynamic method call time = 18 nanoseconds **
- reflection method call time = 36 nanoseconds
- field method invoke dynamic call time = 8 nanoseconds
- field method reflection call time = 6 nanoseconds
- regular method call time = 70 nanoseconds **
- invoke dynamic method call time = 84 nanoseconds
- reflection method call time = 211 nanoseconds
- field method invoke dynamic call time = 153 nanoseconds
- field method reflection call time = 40 nanoseconds
There is a performance improvement over reflection but it is complicated. It depends on how many times you make the calls. You probably only care if the code is in a tight loop.
The benchmarks that I have seen recently show 15x improvement over plain reflection, and only 2.5x slower than invoking a method in the normal way. But you know the old saying, believe nothing you hear and only 1/2 of what you read.
I figure I would try it out.
I have been fooling around with reflection and invokedynamic for a bit now. see A short write up on invoke dynamic.
Here are the results that I get using JDK 1.8 build 94.
One million calls (results are in nano seconds):
10,000 thousand calls
regular method call time = 103
invoke dynamic method call time = 116
reflection method call time = 252
100,000 thousand calls (after warmup).
regular method call time = 46
invoke dynamic method call time = 112
reflection method call time = 171
1,000,000 calls
regular method call time = 23
invoke dynamic method call time = 35
reflection method call time = 30
Reflection is faster at 1M than invoke dynamic. Ummm... Odd.
10,000,000 calls
regular method call time = 34
invoke dynamic method call time = 24
reflection method call time = 43
Now invoke dynamic is faster than a regular method call!
Now 100,000,000
regular method call time = 22
invoke dynamic method call time = 24
reflection method call time = 28
At this point, the JIT compiler takes all of the pain away. If you can't spare an extra 2 to 6 nano seconds, then you need to have some coping skills.
Here is the code to recreate the tests (also follow the above link):
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class thisClass = lookup.lookupClass(); // (who am I?)
MethodType methodType;
MethodHandle methodHandle;
Create an employee object.
Employee employee = new Employee();
Look up getName with invoke dynamic (see blog for a lot more examples, link above).
//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);
Look up Employee.getName with reflection.
//Lookup reflection
Method method = Employee.class.getMethod("getName", new Class<?>[]{});
name = (String) method.invoke(new Employee());
System.out.println("reflection " + name);
Start time, end time, number of iterations (times), calculated times, the usual suspects.
long start = 0;
long end = 0;
long times = 100_000_000;
long regularTime;
long invokeDynamicTime;
long reflectionTime;
long count=0;
Now let's warm up the JVM.
//warm up
for (int index =0 ; index < times; index++) {
employee.getName();
name = (String) methodHandle.invokeExact(employee);
name = (String) method.invoke(employee);
}
Let's calculate regular method invocation.
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. I added the count, so my code would not get jitted away somehow.
Now let's calculate invokeDyanmic time.
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);
Now let's calculate reflection time.
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);
I decided to add one more to the mix. If you really just want the property, then what if you just access the field directly.
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
Ok, here is the code for the field access which is 4x faster than using employee.getName().
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);
}
Now the actual field reflection / invoke dynamic code:
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);
I guess OP means InvokeDynamic as mentioned here http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html for method invokation. I have never used myself but this post looks very descriptive it quotes
"The performance difference may not matter for a library doing a few reflected calls, especially if those calls are mostly to dynamically set up a static structure in memory against which it can make normal calls. But in a dynamic language, where every call must use these mechanisms, it's a severe performance hit."
I think you mean reflection by dynamic invoke. The cost of reflection is a little bit high than normal method invocation.
Reflection has many usages, for example I use it extensively for ui-data binding..
精彩评论