Компилятор Sun HotSpot JIT автоматически применяет final к локальным переменным Java?

Я слышал, что это так, но не смог найти точного источника в Интернете, чтобы это подтвердить.

Предыстория: коллега любит делать свои локальные переменные final. Одна из причин этого - производительность. Я утверждаю, что компилятор Java HotSpot Just In Time автоматически обнаруживает инвариантные локальные переменные и делает их final, поэтому делать это самим не дает никакого преимущества с точки зрения производительности.

Обратите внимание, что я не спрашиваю, является ли создание локальных переменных final хорошей практикой кодирования, потому что по этому поводу уже есть много (не по теме) SO-вопросов.

РЕДАКТИРОВАТЬ: mrhobo хорошо замечает оптимизацию байт-кода для целочисленных литералов. Я должен был привести пример кода, о котором я говорил, с моим вопросом:

Object doSomething(Foo foo) {
    if (foo == null) {
        return null;
    }

    final Bar bar = foo.getBar();
    final Baz baz = this.bazMap.get(bar);

    return new MyObject(bar, baz);
}

Как вы думаете, в этом сценарии происходит такая же оптимизация, потому что bar и baz оба отмечены final? Или HotSpot автоматически определяет, что они не меняются в рамках метода, и в любом случае рассматривает их как final?

Похожие вопросы


person Steve K    schedule 07.03.2014    source источник
comment
Коллега любит делать свои локальные переменные окончательными. Одна из причин этого - производительность. = ›Это не улучшит производительность. Так что остальная часть обсуждения не нужна! С полями дело обстоит иначе: последнее поле - это не то же самое, что неокончательное поле.   -  person assylias    schedule 07.03.2014
comment
@assylias, который не улучшит производительность. == ›ссылка?   -  person Steve K    schedule 07.03.2014
comment
Тот факт, что байт-код такой же (как указано в одной из опубликованных вами ссылок), является сильным намеком. Но если задуматься, конечные поля имеют очень специфическую семантику в модели памяти Java, которая отличает их от незавершенных полей, что, возможно, влияет на производительность. Однако локальная переменная - это локальная переменная - я не могу себе представить, как ее окончательная версия может повлиять на производительность.   -  person assylias    schedule 07.03.2014
comment
Я вижу, как байт-код меняется с iload на iconst при изменении фактически конечных локальных переменных ints на final ..   -  person Lodewijk Bogaards    schedule 07.03.2014
comment
@mrhobo iconst обычно означает буквальный. Итак, если вы напишете final int i = 1;, у вас будет значок, соответствующий 1. Если вы напишете int i = 1;, вы получите то же самое.   -  person assylias    schedule 07.03.2014
comment
Если вам нужна ссылка, см. Стратегии и тактики повышения производительности платформы Java, написанный двумя людьми, которые работали над оптимизаторами точек доступа Sun. (Заявитель: я родственник одного из авторов.)   -  person keshlam    schedule 07.03.2014
comment
Вы можете прочитать SSA, чтобы понять, почему final для локальных переменных в Java (const в С ++ - это отдельная тема, поскольку локальные переменные могут изменять свое значение, если они куда-то переданы) совершенно неинтересно с точки зрения компилятора для оптимизации.   -  person Voo    schedule 08.03.2014


Ответы (1)


Чтобы понять, почему final для локальных переменных совершенно неинтересен для компилятора, будет полезно немного узнать, как работают компиляторы. По сути, ни один компилятор не работает с исходным кодом (или байт-кодом), вместо этого они разбирают его в какое-то промежуточное представление (часто несколько разных при применении оптимизаций). И почти каждый известный мне компилятор использует ту или иную форму static-single assignment или короткую форму SSA для своего промежуточного представления.

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

y = 4
x = 5
y = 6
z = x + y

В форме SSA это выглядит примерно так:

y_1 = 4
x_1 = 5
y_2 = 6
z_1 = y_2 + x_1

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

PS: циклы и ветвления немного усложняют это, но я не хочу слишком отвлекать от обсуждения - хотя в вики-статье есть краткое объяснение того, как решить эти проблемы.

person Voo    schedule 11.03.2014
comment
Спасибо @Voo. Использует ли компилятор Java форму SSA для объектов, а также такие литералы, как int? - person Steve K; 11.03.2014
comment
Форма @Steve SSA работает с переменными, а не с самими объектами, это важное отличие. Так что да, здесь нет реальной разницы между переменной, указывающей на объект, и переменной, содержащей примитив. - person Voo; 11.03.2014