#java #garbage-collection #jvm
#java #сборка мусора #jvm
Вопрос:
В проекте, который я поддерживаю, я нашел класс java с методом «fn», подобным показанному ниже
class Test{
public void fn(){
String METHOD_NAME = "fn";
...
sysout("In " METHOD_NAME);
}
}
Программа выполняется бесконечно, а метод ‘fn’ вызывается непрерывно и с очень высокой частотой. Вопрос в том
- будет ли переменная METHOD_NAME создаваться каждый раз при вызове fn()?
- будет ли JVM выполнять некоторую оптимизацию, чтобы переменная METHOD_NAME не собиралась мусором и не использовалась повторно при следующем вызове fn()?
- улучшилась бы производительность, если бы я сделал переменную общедоступной статической конечной?
(На самом деле таких функций так много, что я хочу знать, стоит ли менять их все)
(Я предполагаю, что пул строк играет здесь некоторую роль)
Спасибо, Киран Мохан
Комментарии:
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. Ваш ответ очень низкого качества и, скорее всего, также неверен.