Подтвердить что ты не робот

Очистите ArrayList или просто создайте новый, и пусть старый будет собран мусором?

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

В частности, у меня есть ArrayList<Rectangle>, называемый list. Когда возникает определенное условие, мне нужно удалить list и пополнить его другим содержимым. Должен ли я позвонить list.clear() или просто создать новый ArrayList<Rectangle> и позволить старому собрать мусор? Каковы плюсы и минусы каждого подхода?

4b9b3361

Ответ 1

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

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

Освобождение контейнера и создание нового имеет смысл, когда размер новых данных может отличаться от того, что было до этого. Конечно, вы можете добиться аналогичного эффекта, вызвав clear() в сочетании с trimToSize().

Ответ 2

Преимущество повторного использования ArrayList (например, путем вызова clear) состоит в том, что вы избегаете накладных расходов по выделению нового и затрат на его наращивание... если вы не предоставили хорошую подсказку initialCapacity.

Недостатки утилизации ArrayList включают в себя следующее:

  • Метод clear() должен присвоить null каждому (используемому) слоту в резервном массиве ArrayList.

  • clear() не изменяет размер резервного массива для освобождения памяти. Поэтому, если вы неоднократно заполняете и очищаете список, он будет (постоянно) использовать достаточно памяти для представления самого большого списка, с которым он сталкивается. Другими словами, вы увеличили объем памяти. Вы можете бороться с этим, вызывая trimToSize(), но это создает мусорный объект, и так далее 1.

  • Есть проблемы с местностью и поколениями, которые могут повлиять на производительность. Когда вы несколько раз перезапускаете ArrayList, объект и его резервный массив, скорее всего, останутся в собственности. Это означает, что:

    • Объекты списка и объекты, представляющие элементы списка, вероятно, находятся в разных областях кучи, что потенциально увеличивает пропуски TLB и трафик страницы, особенно во время GC.

    • Присвоение ссылок (молодого поколения) в (резервный) массив поддержки списка может привести к накладным расходам на запись... в зависимости от реализации GC.

Невозможно точно смоделировать компромиссы производительности для реального приложения. Просто слишком много переменных. Тем не менее, "полученная мудрость" заключается в том, что утилизация обычно НЕ является хорошей идеей, если у вас достаточно памяти 2 и наполовину приличный сборщик мусора.

Стоит также отметить, что современная JVM может очень эффективно распределять объекты. Ему просто нужно обновить указатель кучи "free" и написать 2 или 3 слова заголовка объекта. Обнуление памяти выполняется GC... и помимо выполняемой работы это примерно эквивалентно работе, которую выполняет clear() для обнуления ссылок в списке, который подвергается переработке.


1 - Для производительности было бы лучше создать новый ArrayList, чем вызывать clear(), за которым следует trimToSize (...).С последним вы получаете как накладные расходы на сборку мусора, так и накладные расходы на излишний обнуление.

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


Мой совет - НЕ перерабатывать объекты ArrayList если у вас нет явной необходимости минимизировать скорость создания (мусора) объектов; например, потому что это единственный вариант для уменьшения (вредных) пауз в GC.

При прочих равных условиях в современной JVM Hotspot я понимаю, что вы получите наилучшую производительность, выполнив следующие действия:

  • Выделение новых объектов ArrayList, а не переработка.
  • Используйте точные подсказки initialSize при выделении объектов списка. Лучше немного переоценить, чем немного недооценить.

Ответ 3

Поскольку интересные моменты уже были написаны, вы можете думать об этом даже на один уровень глубже.

Я не понял этого, чем прочитал статью о шаблоне разрушителя, см. Как работает шаблон прерывания LMAX?

Возможно не только повторно использовать базовую коллекцию, вы можете повторно использовать также сущности внутри коллекции.

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

Это решение на одном уровне лучше в точке просмотра GC. Но это явно особый случай, не полезный для каждой проблемы.

Ответ 4

Это не имеет значения...

Функция List.clear() устанавливает ссылки на внутренние массивы на нуль. Эффективно настраивать объекты для сбора мусора, если ссылок больше нет.

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

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