Удаляет ли компилятор точки доступа Java мертвый код, включающий переменные экземпляра, известное конечное состояние

В следующем коде видно, что baa всегда ложно. Обнаружит ли это компилятор точки доступа и удалит ли вызов метода isBaa() и содержащийся в нем код?

public class Foo() {
    public final boolean baa = false;
    public isBaa() {
        return baa;
    }
}

Такое использование

static final Foo foo = new Foo();

public m() {
    if (foo.isBaa()) {
        // code here...
    }
}

Я хотел бы знать, сравнивается ли этот код с добавлением

static final Foo foo = new Foo();
static final BAA = foo.isBaa();

и проверка с

if (BAA) ...

Интересует скорость выполнения после того, как точка доступа сделала свое дело. Можно ли как-то увидеть результат компиляции точки доступа? Или мы должны сделать вывод из деталей реализации используемого компилятора горячей точки.

Вариант использования заключается в поддержке isDebugEnabled() с помощью конечной переменной в коде, очень чувствительном к производительности. Поэтому меня интересует, оптимизирован ли сам вызов метода.


person teknopaul    schedule 04.09.2017    source источник
comment
Возможно, более надежным будет использование статического финала.   -  person Dave Newton    schedule 04.09.2017
comment
Надежный означает, что в некоторых ситуациях это работает, а в некоторых нет?   -  person teknopaul    schedule 04.09.2017
comment
Не уверен. Я знаю, что для некоторых импликаций код, обернутый статическими финалами, можно полностью удалить, но это было давно (и Android). Компилятор проверит статические значения во время компиляции - он не проводит логического анализа, поэтому использование статического финала гарантированно (?) сделает то, что вы ожидаете. Я предполагаю, что нестатический код не будет работать во время компиляции (это достаточно легко проверить), но будет JIT-компилирован после прогрева. Но извините, я угадал :/   -  person Dave Newton    schedule 04.09.2017


Ответы (1)


Отвечая на мой собственный вопрос...

Я использовал время, чтобы измерить, когда точка доступа полностью избавилась от кода. то есть, если код в цикле больше не добавляет времени к времени выполнения цикла, он был скомпилирован.

  • static final логические проверки могут быть полностью скомпилированы.
  • вызовы статических методов могут быть скомпилированы.
  • методы экземпляра, даже если они помечены как final, таковыми не являются.

В моих тестах на окончательных вызовах метода ibm jdk8, которые ничего не делают, потребовалось ~ 6 тактов.

Документы Hotspot от IBM подразумевают, что методы конечного экземпляра могут быть встроены, но тестирование показывает, что это все еще требует затрат. Я предполагаю, что будущие виртуальные машины смогут еще больше оптимизировать это.

В моих тестах кажется, что компиляция горячих точек также влияет на то, как циклы распределяются между ядрами ЦП.

for(; i < Integer.MAX_VALUE ; i++)

Волшебным образом работает на всех 4 процессорах (в среднем 1/4 тактового цикла)

for(; i < Integer.MAX_VALUE ; i++) if (false) ...

Занимает в среднем 1 такт

Таким образом, даже код, скомпилированный в пустую точку, может повлиять на оптимизацию окружающего кода.

person teknopaul    schedule 04.09.2017
comment
Я бы поставил под сомнение ваши методы измерения. Если у вас есть такой оператор, как if(false) …, он уже будет удален во время компиляции. Аналогично, любая переменная, объявленная как final boolean baa = false;, является константой времени компиляции, и каждый доступ для чтения заменяется значением false уже во время компиляции. Для этого переменная не обязательно должна быть static. Является ли метод final или нет, на самом деле не имеет значения, поскольку JVM достаточно умна, чтобы распознать, что он нигде не был переопределен, и в результате его можно встроить в любом случае. - person Holger; 05.09.2017
comment
Я рекомендую использовать javap -c для просмотра байт-кода. Если в байт-коде нет разницы, измерение разной производительности подразумевает проблему с эталонным тестом. Вы можете использовать -XX:+PrintCompilation во время выполнения, чтобы узнать, что делает JVM, и -XX:+PrintAssembly, чтобы увидеть результаты. Если вы погуглите эти параметры, вы найдете много ресурсов по этой теме. - person Holger; 05.09.2017