оптимизация jvm для строковых переменных в методах

#java #garbage-collection #jvm

#java #сборка мусора #jvm

Вопрос:

В проекте, который я поддерживаю, я нашел класс java с методом «fn», подобным показанному ниже

 class Test{

public void fn(){
    String METHOD_NAME = "fn";
    ...
    sysout("In "   METHOD_NAME);
}
}
  

Программа выполняется бесконечно, а метод ‘fn’ вызывается непрерывно и с очень высокой частотой. Вопрос в том

  1. будет ли переменная METHOD_NAME создаваться каждый раз при вызове fn()?
  2. будет ли JVM выполнять некоторую оптимизацию, чтобы переменная METHOD_NAME не собиралась мусором и не использовалась повторно при следующем вызове fn()?
  3. улучшилась бы производительность, если бы я сделал переменную общедоступной статической конечной?
    (На самом деле таких функций так много, что я хочу знать, стоит ли менять их все)

(Я предполагаю, что пул строк играет здесь некоторую роль)

Спасибо, Киран Мохан

Комментарии:

1. Кстати: ввод-вывод обычно намного дороже, чем создание объекта. Если вы не можете избежать ввода-вывода или создать много объектов, которые вы можете оптимизировать, это, вероятно, не будет иметь большого значения.

Ответ №1:

Да, переменная METHOD_NAME будет создаваться каждый раз, когда вы вводите метод, но это очень, очень дешевая операция (на самом деле создание 2 переменных обходится так же дорого, как и создание 1).

Значение (т. Е. String объект) "fn" не будет воссоздано заново, а будет получено из пула постоянных строк.

Однако выражение "In " METHOD_NAME будет пересчитываться и каждый раз вызывать создание нового String объекта, поскольку оно не является выражением, постоянным во время компиляции.

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

Комментарии:

1. просто для завершения: "In " METHOD_NAME также приведет к созданию нового StringBuilder!

2. @Carlos: это правильно (если METHOD_NAME не является константой (т. е. не static final )).

Ответ №2:

Переменные не собирают мусор — это объекты.

«fn» — это строковый литерал, поэтому он будет интернирован. Сбор мусора производиться не будет (по крайней мере, пока этот загрузчик классов активен; не уверен, есть ли один пул стажеров на CL или один для всей JVM, но это, вероятно, не имеет значения), и один и тот же объект string будет использоваться при каждом вызове.

Если вы сделаете это общедоступным статическим финалом, это определенно будет улучшением, поскольку конкатенация может выполняться компилятором, а не во время выполнения.

Если вы сделаете это окончательным внутри метода (т. Е. все еще как локальную переменную), это может иметь тот же эффект — я не уверен.

Комментарии:

1. проверка байтового кода: выполнение его окончательным внутри цикла будет иметь тот же эффект — компилируется без конкатенации — но присвоение переменной все еще остается (вероятно, устраняется JIT).

Ответ №3:

«fn» будет интернирован. Следовательно, один и тот же объект будет использоваться снова и снова.

В худшем случае вы можете просто заменить его на :

 String METHOD_NAME = "fn".intern();
  

Хотя я думаю, что это не нужно.

Сделать его общедоступным статическим окончательным — это хорошо.

Комментарии:

1. Не предлагайте использовать intern() для строкового литерала! В этом всегда нет необходимости. По определению.

2. intern может быть относительно дорогостоящей (требуется поиск строки в пуле), не рекомендуется внутри цикла (несмотря на то, что в этом нет необходимости)

Ответ №4:

Насколько мне известно, METHOD_NAME — ссылка на строку ‘fn’ будет выделяться при каждом вызове fn(). Однако объект String ‘fn’ должен быть выделен один раз, поскольку он является строковой константой и будет помещен в пул строк.

Замена его общедоступным статическим финалом может быть хорошей идеей, но это скорее для стиля программирования, чем для повышения производительности.

Ответ №5:

Строковые литералы помещаются в пул констант. Нет никакого смысла помещать строку в статический финал — такое поведение гарантируется JLS.

(и да, строка также будет интернирована, хотя это не особенно важно для ваших проблем)

Ответ №6:

будет ли переменная METHOD_NAME создаваться каждый раз при вызове fn()?

Переменная была бы «создана» (лучше «установлена»), но строка — нет (поскольку это внутренняя строка, находящаяся в пуле строк JVM). Итак, это просто новая ссылка на ту же строку.

будет ли JVM выполнять некоторую оптимизацию, чтобы переменная METHOD_NAME не собиралась мусором и не использовалась повторно при следующем вызове fn()

Переменная METHOD_NAME — это просто имя для ссылки. Строка, на которую ссылается, скорее всего, находится в пуле строк.

улучшилась бы производительность, если бы я сделал переменную общедоступной статической конечной?

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

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

Ответ №7:

я предпочитаю публичный статический финал, который увеличит производительность.

Комментарии:

1. Ваш ответ очень низкого качества и, скорее всего, также неверен.