2

私は単純なプロジェクトに取り組んでおり、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 の詳細を比較するドキュメントはありますか?

4

1 に答える 1