Имеет ли смысл такая форма управления памятью в Java? - PullRequest
5 голосов
/ 01 сентября 2011

В жизненном цикле моего приложения я должен заново создать ArrayList, который содержит другие ArrayList объектов (считывая их из хранилища). ArrayList всегда присваивается одному и тому же элементу данных в классе, по существу, оставляя старые ArrayList-of-ArrayLists висячими (недоступными или недоступными).

Насколько я понимаю, в отличие от C ++, это не приводит к утечке памяти, поскольку система знает, когда объект становится недоступным по ссылкам, и освобождает память, когда / как считает нужным.

Тем не менее, старые привычки трудно преодолеть, и я почти инстинктивно тянусь, чтобы «помочь» системе, выполнив некоторую очистку самостоятельно перед повторным созданием этого ArrayList-of-ArrayLists:

for (InnerArray aList : outerArray)
  aList.clear();
outerArray.clear();

Мои вопросы:

  1. Это избыточно?
  2. Я делаю больше вреда, чем пользы?
  3. Это хорошо в любом случае?
  4. Почему?

Ответы [ 3 ]

9 голосов
/ 01 сентября 2011

Это избыточно.Вы не помогаете освободить эти объекты, потому что сборщик мусора уже определит, что они недоступны.Вы не можете сделать их более недоступными, чем они уже есть.Таким образом, вы тратите немного времени на обработку чего-то, что ничего не дает.

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

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

3 голосов
/ 01 сентября 2011

1) Это избыточно?

Да.

2) Я делаю больше вреда, чем пользы?

Да.

3) Это хорошо в любом случае?

Нет.

4) Почему?

Вызов clear() для ArrayList изменяет поле size списка и затем тщательно присваивает null элементам его резервного массива, которые только что стали недействительными.Код clear() должен сделать это, потому что ссылки в этих элементах могут сделать другие объекты доступными;то есть утечка памяти.

Однако, когда ArrayList становится недоступным, сборщик мусора не будет никогда смотреть на любые элементов резервного массива,Процесс маркировки GC только перебирает достижимые объекты, а процесс восстановления не смотрит на содержимое мусорных объектов / массивов.

Таким образом, в основном, вызывая clear() для объекта, который он собирается стать недоступнымэто полная трата циклов ЦП и пропускной способности памяти / ВМ.(И, конечно, является излишним код, следующий парень собирается почесать голову о ...)


На самом деле, это даже спорно ли вызова clear, а затем повторно использовать список являетсяХорошая идея:

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

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

Существует ли сценарий, который действительно оправдывает вызов clear()?

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

Также может быть полезно очистить / повторно использовать списки на платформе с ограниченной памятью и / или медленным сборщиком мусора.Тем не менее, я бы не стал пытаться провести эту «оптимизацию», если бы у меня не было СИЛЬНОГО доказательства того, что это проблема.(Этот вид оптимизации усложняет ваш код и может привести к проблемам с производительностью, если он выполняется неправильно.)

3 голосов
/ 01 сентября 2011
  1. Да - Честно говоря, я просто не понимаю. если вам больше не нужен объект, просто убедитесь, что вы больше не можете получить к нему доступ, и у вас все хорошо!
  2. yup - вызов может использовать вычислительную мощность, сборщик мусора, вероятно, будет использовать меньше, чтобы избавиться от объекта. Это также может сбить с толку, как предположил Нейт.
  3. Нет - ничего хорошего не вижу, извините.
  4. Смотрите выше и добро пожаловать на Java! Теперь вы можете сосредоточиться на забавных вещах:)

P.S. Я не уверен в том, что сейчас скажу, но функция clear() может удалить элементы из ArrayList, просто убедившись, что вы больше не можете получить к ним доступ через переменную ArrayList. Вероятно, это не «уничтожит» их, но только сделает их пригодными для сбора мусора. Было бы неплохо узнать, как реализована эта функция ...

P.P.S. У вас может возникнуть соблазн вызвать GC самостоятельно, не делайте этого! См связанный вопрос .

EDIT:

Вот clear() от ArrayList:

public void clear()
{
    if (size > 0)
    {
        modCount++;
        // Allow for garbage collection.
        Arrays.fill(data, 0, size, null);
        size = 0;
    }
}
...