Отражение Java Вызовы методов дают результат быстрее, чем Fields? - PullRequest
4 голосов
/ 04 января 2011

Я выполнял микробенчмаркинг некоторого кода (пожалуйста, будьте любезны) и натолкнулся на эту загадку: при чтении поля с использованием отражения вызывается метод получателя быстрее, чем чтение поля.

Простой тестовый класс:

private static final class Foo {
    public Foo(double val) {
        this.val = val;
    }
    public double getVal() { return val; }
    public final double val; // only public for demo purposes
}

У нас есть два отражения:

Method m = Foo.class.getDeclaredMethod("getVal", null);
Field  f = Foo.class.getDeclaredField("val");

Теперь я называю два отражения в цикле, invoke в методе и get в поле.Первый прогон выполняется для прогрева виртуальной машины, второй прогон выполняется с 10M итерациями. Вызов метода последовательно на 30% быстрее, но почему? Обратите внимание, что getDeclaredMethod и getDeclaredField не вызываются в цикле.Они вызываются один раз и выполняются для одного и того же объекта в цикле.

Я также попробовал несколько незначительных изменений: сделал поле не финальным, транзитивным, закрытым и т. Д. Все эти комбинации привели к статистически сходнымпроизводительность.

Редактировать: Это на WinXP, Intel Core2 Duo, Sun JavaSE build 1.6.0_16-b01, работает под jUnit4 и Eclipse.

Ответы [ 3 ]

3 голосов
/ 04 января 2011

Мое обоснованное предположение было бы различием в том, как реализованы getDeclaredField и getDeclaredMethod: при каждом вызове getDeclaredField необходимо проверять тип и размер переменной, чтобы вернуть фактический объект или примитивный тип, getDeclaredMethodвернуть указатель на один и тот же метод, который статически заботится обо всем остальном.

Редактировать :

Мое объяснение аналогично: метод содержится в памяти только один раз для каждого класса, в то время как каждый экземпляр объекта может иметь разные значения свойств.Когда вы получаете значение свойства, выполняя вызов метода (все еще используя только указатель метода), компилятор оптимизировал метод для доступа к параметру, зная точную иерархию классов и т. Д., А когда вы получаете значение свойства с помощью «get»", вы позволяете отражениям выполнять работу метода getter, и, очевидно, не может быть никакой оптимизации компилятора.

1 голос
/ 29 февраля 2012

В вашем микробенчмарке вызов метода происходит быстрее из-за оптимизаций, выполненных JVM / Hotspot с помощью вашего цикла.

Измените свой микробенчмак:

Создайте цикл, в котором: прочитайте значение по Reflection, затем увеличьте 1 (например), а затем присвойте тому же полю через Reflection. И вне цикла, сделайте окончательное чтение и System.out.println его ...

Выполните два варианта (поле против метода), и вы увидите, что реальная разница как раз противоположна: вызовы метода на самом деле на 30-40% медленнее.

Привет

0 голосов
/ 04 января 2011

означает ли это, что double d = Foo.getVal() на 30% быстрее, чем double d = Foo.val?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...