Использует ли final для переменных в Java улучшенную сборку мусора?

Сегодня у моих коллег и меня обсуждается использование ключевого слова final в Java для улучшения сбора мусора.

Например, если вы пишете такой метод, как:

 public Double doCalc(final Double value) { final Double maxWeight = 1000.0; final Double totalWeight = maxWeight * value; return totalWeight; } 

Объявление переменных в final методе поможет сборщику мусора очистить память от неиспользуемых переменных в методе после выхода метода.

Это правда?

Вот несколько другой пример: один с полями конечного ссылочного типа, а не с конечными значениями локальных переменных типа значения:

 public class MyClass { public final MyOtherObject obj; } 

Каждый раз, когда вы создаете экземпляр MyClass, вы создаете исходящую ссылку на экземпляр MyOtherObject, и GC должен будет следовать этой ссылке для поиска живых объектов.

В JVM используется алгоритм GC с меткой развертки, который должен проверять все живые рефери в локальных местах GC (как и все объекты в текущем стеке вызовов). Каждый живой объект «помечен» как живой, и любой объект, на который ссылается живой объект, также помечен как живой.

По завершении фазы метки GC прокручивается через кучу, освобождая память для всех немаркированных объектов (и уплотняя память для оставшихся живых объектов).

Кроме того, важно признать, что память кучи Java разделена на «молодое поколение» и «старое поколение». Все объекты изначально выделяются в молодое поколение (иногда называемое «детской»). Поскольку большинство объектов недолговечны, GC более агрессивно относится к освобождению последнего мусора от молодого поколения. Если объект переживает цикл сбора молодого поколения, он перемещается в прежнее поколение (иногда называемое «поколение поколений»), которое обрабатывается реже.

Итак, с головы до ног, я скажу «нет», «окончательный» модификатор не помогает GC уменьшить нагрузку ».

На мой взгляд, лучшей страtagsей оптимизации управления памятью на Java является устранение ложных ссылок как можно быстрее. Вы можете сделать это, назначив «null» ссылке на объект, как только вы закончите использовать его.

Или, еще лучше, минимизируйте размер каждой области декларации. Например, если вы объявляете объект в начале метода 1000 строк, и если объект остается живым до закрытия области действия этого метода (последняя закрывающая фигурная скобка), тогда объект может оставаться в живых намного дольше, чем на самом деле необходимо.

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

Объявление локального значения переменной не влияет на garbage collection, это означает, что вы не можете изменять переменную. Ваш пример выше не должен компилироваться при изменении переменной totalWeight которая была отмечена как final . С другой стороны, объявление примитивного ( double а не Double ) final позволит этой переменной быть встроенным в вызывающий код, что может привести к некоторой памяти и повышению производительности. Это используется, когда у вас есть несколько public static final Strings в classе.

В общем, компилятор и среда выполнения оптимизируют, где это возможно. Лучше написать код надлежащим образом и не пытаться быть слишком сложным. Используйте final если вы не хотите, чтобы переменная была изменена. Предположим, что любая простая оптимизация будет выполняться компилятором, и если вас беспокоит производительность или использование памяти, используйте профилировщик для определения реальной проблемы.

Нет, это категорически неверно.

Помните, что final не означает постоянную, это просто означает, что вы не можете изменить ссылку.

 final MyObject o = new MyObject(); o.setValue("foo"); // Works just fine o = new MyObject(); // Doesn't work. 

Может быть какая-то небольшая оптимизация, основанная на знаниях о том, что JVM никогда не придется изменять ссылку (например, не иметь проверки, чтобы увидеть, изменилась ли она), но она была бы настолько незначительной, чтобы не беспокоиться.

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

Некоторые моменты, которые нужно прояснить:

  • Отказ от ссылки не должен помогать GC. Если бы это произошло, это означало бы, что ваши переменные превышены. Одним из исключений является случай кумовства.

  • На Java не существует распределения по стопам.

  • Объявление переменной final означает, что вы не можете (при нормальных условиях) назначить новое значение этой переменной. Поскольку в финале ничего не говорится о сфере видимости, он ничего не говорит о его влиянии на GC.

Ну, я не знаю об использовании «финального» модификатора в этом случае или его влиянии на GC.

Но я могу сказать вам следующее: ваше использование значений в штучной упаковке, а не примитивов (например, Double вместо double) будет выделять эти объекты в куче, а не в стеке, и создаст ненужный мусор, который GC должен будет очистить.

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

Конечные переменные не могут быть изменены после первоначального присваивания (принудительно выполняются компилятором).

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

Вы должны знать, что final позволяет компилятору делать предположения о том, что нужно оптимизировать. Код встраивания и не включая код, который, как известно, недоступен.

 final boolean debug = false; ...... if (debug) { System.out.println("DEBUG INFO!"); } 

Println не будет включен в байтовый код.

GC действует на недостижимые ссылки. Это не имеет ничего общего с «окончательным», что является просто утверждением одноразового задания. Возможно ли, что GC какого-то ВМ может использовать «окончательный»? Я не понимаю, как и почему.

Существует не очень известный угловой случай с коллективными сборщиками мусора. (Для краткого описания читайте ответ benjismith для более глубокого понимания, прочитайте статьи в конце).

Идея в генерации GC заключается в том, что большую часть времени нужно учитывать только молодые поколения. Корневое местоположение сканируется для ссылок, а затем проверяются объекты молодого поколения. Во время этой более частых разверток объект старого поколения не проверяется.

Теперь проблема возникает из-за того, что объекту не разрешено ссылаться на более молодые объекты. Когда объект долгоживущего (старого поколения) получает ссылку на новый объект, эта ссылка должна быть явно отслежена сборщиком мусора (см. Статью IBM о сборщике JVM hotspot ), что фактически влияет на производительность GC.

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

Конечно, как указано многими, ключевое слово final не влияет на сборщика мусора, но оно гарантирует, что эта ссылка никогда не будет изменена на младший объект, если этот объект выживет в младших коллекциях и превратит его в более старую кучу.

Статьи:

IBM по сбору мусора: история , в JVM Hotspot и производительность . Они могут быть более недействительными, поскольку это датируется 2003/04 годом, но они дают некоторое легко читаемое представление о GC.

Sun on Tuning garbage collection

final по локальным переменным и параметрам не имеет никакого значения для созданных файлов classов, поэтому не может повлиять на производительность выполнения. Если class не имеет подclassов, HotSpot рассматривает этот class так, как если бы он был окончательным в любом случае (он может отменить позже, если class, который нарушает это предположение, загружен). Я считаю, что final методы очень похожи на classы. final в статическом поле может позволить переменной интерпретироваться как «константу времени компиляции» и оптимизацию, которая должна выполняться javac на этой основе. final на полях позволяет JVM некоторая свобода игнорировать происходит до отношений.

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

Ответ на ваш вопрос является решительным нет.

Все методы и переменные могут быть переопределены в подclassахdefault. Если мы хотим сохранить подclassы от переопределения членов суперclassа, мы можем объявить их окончательными с использованием ключевого слова final. Для eg- final int a=10; final void display(){......} Выполнение окончательного метода гарантирует, что функциональность, определенная в суперclassе, никогда не будет изменена. Точно так же значение конечной переменной никогда не может быть изменено. Конечные переменные ведут себя как переменные classа.

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

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

Единственный раз, когда я предпочитаю объявлять локальные переменные как final, это когда:

  • Я должен сделать их окончательными, чтобы их можно было разделить с каким-то анонимным classом (например: создать stream демона и позволить ему получить доступ к некоторому значению из метода encoding)

  • Я хочу сделать их окончательными (например: какое-то значение, которое не должно / не должно быть переопределено по ошибке)

Помогают ли они в быстрой сборке мусора?
AFAIK объект становится кандидатом коллекции GC, если он имеет нулевые ссылки на него, и в этом случае также нет гарантии, что они будут немедленно собраны мусором. В целом, считается, что сильная ссылка умирает, когда она выходит из области видимости, или пользователь явно переназначает ее нулевой ссылкой, поэтому объявление их окончательным означает, что ссылка будет существовать до тех пор, пока не будет существовать метод (если его область явно не сужается до конкретный внутренний блок {}), поскольку вы не можете переназначить конечные переменные. Поэтому я думаю, что compilation Garbage Collection «final» может ввести нежелательную возможную задержку.

  • Log4j: Как настроить простейшее возможное ведение журнала файлов?
  • Можно ли создать проект java только один раз, используя eclipse и поделиться?
  • Есть ли утилита отражения Java для глубокого сравнения двух объектов?
  • Архитектура Java EE. Являются ли DAO по-прежнему рекомендуемыми при использовании ORM, таких как JPA 2?
  • Как сохранить разрывы строк при использовании jsoup для преобразования html в обычный текст?
  • Исключение Java JDBC MySQL: «Операция не разрешена после закрытия ResultSet»
  • Как изменить массив int в Java?
  • Когда Java Thread.sleep запускает InterruptedException?
  • Spring MVC - привязка поля даты
  • Http Получить поддержку Android HttpURLConnection
  • Самый простой способ перебора через Multiset в порядке частоты элементов?
  • Давайте будем гением компьютера.