私は単純なプロジェクトに取り組んでおり、Bean プロパティを取得する必要があります。まず、リフレクションを使用します。次に、パフォーマンスを向上させるために、invokedynamic とメソッド ハンドラーについて調査を行いました。
インボークinvokeExact
はリフレクションよりもはるかに高速ですが、リフレクションよりもはるかに低速です。
テスト環境:
- Win7 32ビット
- ジャワ 7 U 80
- コアによるCPU 3.06GHZ
私が得たtp / msはこれについてです:
mhInvoke * 5 = reflect
reflect * 6 = mhInvokeExact
mhInvokeExact * 10 = direct call
パフォーマンス テストの出力は次のとおりです (2 回実行しました)。
Ref tpms = 10479
mh invoke tpms = 273
mh invoke with convert tpms = 957
mh invoke exact tpms = 78033
invoke directly tpms = 883011
Ref tpms = 14181
mh invoke tpms = 282
mh invoke with convert tpms = 984
mh invoke exact tpms = 88768
invoke directly tpms = 883011
ここに私のテストコードがあります:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
/**
* User: Mark Zang
* Date: 2015/4/28
* Time: 13:00
*/
public class PerfTestAppMain {
String strVar = String.valueOf(System.currentTimeMillis());
public String getStrVar() {
return strVar;
}
static int count = 1024 * 1024 * 16;
public static void main(String[] args) throws Throwable {
ref();
mhInvoke();
mhInvokeConvert();
mhInvokeExact();
invoke();
System.out.println();
System.out.println();
ref();
mhInvoke();
mhInvokeConvert();
mhInvokeExact();
invoke();
}
static void ref() throws Throwable {
PerfTestAppMain bean = new PerfTestAppMain();
Method ref = PerfTestAppMain.class.getMethod("getStrVar");
Object ret = null;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
ret = ref.invoke(bean);
}
long end = System.currentTimeMillis();
System.out.println("Ref tpms = " + ((count) / (end - start)));
}
static void mhInvoke() throws Throwable {
PerfTestAppMain bean = new PerfTestAppMain();
MethodHandle mh = MethodHandles.lookup().findVirtual(
PerfTestAppMain.class,
"getStrVar",
MethodType.methodType(String.class))
.bindTo(bean);
Object ret = null;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
ret = mh.invoke();
}
long end = System.currentTimeMillis();
System.out.println("mh invoke tpms = " + ((count) / (end - start)));
}
static void mhInvokeConvert() throws Throwable {
PerfTestAppMain bean = new PerfTestAppMain();
MethodHandle mh = MethodHandles.lookup().findVirtual(
PerfTestAppMain.class,
"getStrVar",
MethodType.methodType(String.class))
.bindTo(bean);
String ret = null;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
ret = (String) mh.invoke();
}
long end = System.currentTimeMillis();
System.out.println("mh invoke with convert tpms = " + ((count) / (end - start)));
}
static void mhInvokeExact() throws Throwable {
PerfTestAppMain bean = new PerfTestAppMain();
MethodHandle mh = MethodHandles.lookup().findVirtual(
PerfTestAppMain.class,
"getStrVar",
MethodType.methodType(String.class));
String ret = null;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
ret = (String) mh.invokeExact(bean);
}
long end = System.currentTimeMillis();
System.out.println("mh invoke exact tpms = " + ((count) / (end - start)));
}
static void invoke() throws Throwable {
PerfTestAppMain bean = new PerfTestAppMain();
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
bean.getStrVar();
}
long end = System.currentTimeMillis();
System.out.println("invoke directly tpms = " + ((count) / (end - start + 1)));
}
}
invokeExact
コンパイル時に正確な戻り値の型がわからないため、ユース ケースを満たすことができません。リターンの型(強制キャスト)がMethodHandle
の性能を左右する重要な鍵のようです。
MethodType
の戻り値の型が正確であるため、これは予期された結果ではないようです。パフォーマンスを向上させるためにフォースキャストを行うことが依然として重要なのはなぜですか?
これに関する詳細を説明するドキュメントはありますか? また、リフレクションとメソッド ハンドラの使用の impl の詳細を比較するドキュメントはありますか?