[英]Dynamic Invoke feature in java
如果我們使用Dynamic Invoke
,那么應用程序中是否有任何性能改進? 如果不是它的優勢是什么?
所以最后的答案是這樣的:
使用callites調用動態比傳統方法調用更快。
對於字段訪問來說,唯一更快的是直接訪問字段而無需任何方法調用並使用不安全。
答案是沒有調用動態不慢。 它很快。 它非常快。
更新更新:
另一個更新(在星期天晚些時候)我更改了代碼以使用調用站點進行動態調用,這改變了時間。
(所有運行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)
1000次運行
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搞砸了。 請參閱關於調用動態的簡短介紹。
以下是我使用JDK 1.8 build 94獲得的結果。
一百萬次通話(結果以納秒為單位):
10,000個電話
regular method call time = 23
invoke dynamic method call time = 35
reflection method call time = 30
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
現在調用動態比常規方法調用快!
現在100,000,000
regular method call time = 22 invoke dynamic method call time = 24 reflection method call time = 28
此時,JIT編譯器消除了所有的痛苦。 如果你不能多花2到6納秒,那么你需要有一些應對技巧。
以下是重新創建測試的代碼(也按照上面的鏈接):
//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);
通過調用動態查找getName(有關更多示例,請參閱博客,上面的鏈接)。
long start = 0;
long end = 0;
long times = 100_000_000;
long regularTime;
long invokeDynamicTime;
long reflectionTime;
long count=0;
使用反射查找Employee.getName。
//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);
現在讓我們熱身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);
PS我添加了計數,所以我的代碼不會以某種方式被淘汰。
現在讓我們計算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);
我決定再添加一個。 如果你真的只想要這個屬性,那么如果你直接訪問該字段會怎樣。
萬
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
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
1_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
10_000_000
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);
}
100_000_000
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);
好的,這是字段訪問的代碼,比使用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);
我想OP意味着InvokeDynamic,如http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html中提到的方法調用。 我從未使用過自己,但這篇文章看起來非常具有描述性
“對於執行一些反射調用的庫,性能差異可能無關緊要,特別是如果這些調用主要是為了在內存中動態設置一個靜態結構來進行正常調用。但是在動態語言中,每個調用都必須使用這些機制,是一個嚴重的性能損失。“
我認為你的意思是通過動態調用來反映。 反射的成本比普通方法調用略高。
反射有很多用法,例如我廣泛用於ui數據綁定。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.