Делает ли что-нибудь установка объектов Java на null?

112

Я просматривал старые книги и нашел копию "Практической Java" Питера Хаггера. В разделе производительности есть рекомендация устанавливать ссылки на объекты, nullкогда они больше не нужны.

Может ли в Java устанавливать ссылки на объекты для nullповышения производительности или эффективности сборки мусора? Если да, то в каких случаях это проблема? Контейнерные классы? Состав объекта? Анонимные внутренние классы?

Я довольно часто вижу это в коде. Это устаревший совет по программированию или он все еще полезен?

Сэл
источник
2
Профилируйте это. В современных средах выполнения вы не должны увидеть значительного увеличения производительности или объема памяти.
Джейсон Коко,
12
@Jason, профиль? Это предполагает, что я проанализирую достаточно большой набор случаев, чтобы получить достаточно хороший набор результатов, чтобы ответить на этот вопрос. И что я не выбираю набор случаев, когда виртуальная машина достаточно оптимизирована, чтобы замаскировать gc и проблемы с производительностью. Вот почему я спрашиваю об этом здесь. Чтобы понять, в каких случаях это проблема.
sal
1
Дубликат stackoverflow.com/questions/449409/… .
Майкл Майерс

Ответы:

73

Это немного зависит от того, когда вы подумывали обнулить ссылку.

Если у вас есть цепочка объектов A-> B-> C, то, как только A станет недостижимым, все A, B и C будут иметь право на сборку мусора (при условии, что ничто другое не относится ни к B, ни к C). Например, нет необходимости и никогда не было необходимости явно устанавливать для ссылок A-> B или B-> C значение null.

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

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

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;             <-- explicitly set to null
  doSomethingElse();
}

Обоснованием здесь было то, что, поскольку obj все еще находится в области видимости, без явного обнуления ссылки он не станет собираемым мусором до завершения метода doSomethingElse () . И это совет, который, вероятно, больше не актуален для современных JVM : оказывается, JIT-компилятор может определить, в какой момент данная ссылка на локальный объект больше не используется.

Нил Коффи
источник
2
Локальные переменные могут быть оптимизированы машиной. Переменные класса не могут. Я видел, как рабочие потоки (в пуле потоков) не освобождают свои объекты состояния после обработки запроса и, таким образом, закрепляют эти объекты в памяти до тех пор, пока рабочему потоку не будет дана новая задача (которая быстро перезаписала старые объекты состояния новыми). С большими объектами состояния и сотнями рабочих потоков (подумайте: большой http-сервер) это могут быть огромные объемы памяти, которые хранятся и копируются, но никогда больше не будут использоваться.
Брайан Уайт
1
Я, вероятно, должен просто добавить: совет, который я даю выше, - это совет, которому нужно следовать в целом, при условии, что библиотеки с хорошим поведением, виртуальная машина с хорошим поведением и т. Д. задание завершено, ну ... это ошибка в указанной библиотеке пула потоков, которую, возможно, можно было бы обойти, обнулив ссылку на объект, но в равной степени ее можно было бы обойти, используя менее глючную библиотеку пула потоков. Не уверен, что такая ошибка меняет общие принципы проектирования.
Нил Коффи,
25

Нет, это не устаревший совет. Висячие ссылки по-прежнему представляют собой проблему, особенно если вы, скажем, реализуете контейнер расширяемого массива (ArrayList или что-то подобное) с использованием предварительно выделенного массива. Элементы, превышающие «логический» размер списка, должны быть обнулены, иначе они не будут освобождены.

См. Эффективное Java 2-е изд., Правило 6: Устранение устаревших ссылок на объекты.

Крис Джестер-Янг
источник
Это проблема с языком или с реализацией виртуальной машины?
Пабло Санта Крус,
4
Это «семантический» вопрос. По сути, виртуальная машина видит это, поскольку вы предварительно разместили массив. Он ничего не знает о «логическом» размере вашего контейнера. Скажем, у вас есть ArrayList размером 10, поддерживаемый массивом из 16 элементов. ВМ не может знать, что элементы 10..15 фактически не используются; если эти слоты содержат содержимое, они не будут освобождены.
Крис Джестер-Янг,
а как насчет вне контейнерных классов? В композиции объектов, где внутренний объект не освобождается от выделения внешним объектом.
sal
7
@sal Общее практическое правило состоит в том, что если вы не можете ссылаться на него, он будет собираться сборщиком мусора. Поэтому, если внешний объект содержит ссылку на другой объект, при условии, что у внутреннего объекта нет других ссылок, установка единственной ссылки внешнего объекта на null приведет к сборке мусора для всего объекта, включая его потерянные ссылки.
ubermensch
2
В том же Правиле
ACV
10

Поля экземпляра, элементы массива

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

Патологические случаи - это объект, который сохраняет нестандартный экземпляр для всего дерева XML DOM, которое использовалось для его настройки, MBean, который не был незарегистрирован, или единственная ссылка на объект из неразвернутого веб-приложения, которая предотвращает выгрузку всего загрузчика классов .

Поэтому, если вы не уверены, что объект, содержащий ссылку, в любом случае (или даже в этом случае) будет обработан сборщиком мусора, вам следует обнулить все, что вам больше не нужно.

Переменные в области видимости:

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

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;          //   <-- explicitly set to null
  doSomethingElse();
}

становится

{
  {  
     BigObject obj = ...
     doSomethingWith(obj);
  }    //         <-- obj goes out of scope
  doSomethingElse();
}

Длинные плоские области видимости также плохо сказываются на читаемости кода. Внедрение частных методов для разбивки вещей только для этой цели тоже не является чем-то необычным.

Тило
источник
Если вы имеете в виду сильную ссылку, да, это правда, но не для всех ссылок. Слабые ссылки в java могут быть удалены сборщиком мусора.
Джеймс Дринкард,
5

В средах с ограниченным объемом памяти (например, в мобильных телефонах) это может быть полезно. Установив значение null, объекту objetc не нужно ждать, пока переменная выйдет за пределы области видимости для gc'd.

Однако для повседневного программирования это не должно быть правилом, за исключением особых случаев, подобных тому, который процитировал Крис Джестер-Янг.

besen
источник
1

Во-первых, это не значит, что вы устанавливаете объект null. Объясняю это ниже:

List list1 = new ArrayList();
List list2 = list1;

В приведенном выше сегменте кода мы создаем имя переменной ссылки list1на ArrayListобъект, которая хранится в памяти. Так list1ссылается на этот объект, и это не что иное, как переменная. А во второй строке кода мы копируем ссылку list1на list2. Итак, теперь вернемся к вашему вопросу, если я сделаю:

list1 = null;

это означает, что list1больше не ссылается на какой-либо объект, который хранится в памяти, поэтому list2ему также не на что ссылаться. Итак, если вы проверите размер list2:

list2.size(); //it gives you 0

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

Надеюсь, это проясняет концепцию.

Аман Гоэль
источник
0

Одна из причин для этого - исключить устаревшие ссылки на объекты. Вы можете прочитать текст здесь.

Судип Бхандари
источник