Java: Как ArrayList управляет памятью

В моем классе Структур данных мы имеем, изучает класс Java ArrayList, и как это выращивает основной массив, когда пользователь добавляет больше элементов. Это понято. Однако я не могу выяснить, как точно этот класс освобождает память, когда много элементов удалено из списка. При рассмотрении источника существует три метода, которые удаляют элементы:

public E remove(int index) {
 RangeCheck(index);

 modCount++;
 E oldValue = (E) elementData[index];

 int numMoved = size - index - 1;
 if (numMoved > 0)
     System.arraycopy(elementData, index+1, elementData, index,
        numMoved);
 elementData[--size] = null; // Let gc do its work

 return oldValue;
}

public boolean remove(Object o) {
 if (o == null) {
            for (int index = 0; index < size; index++)
  if (elementData[index] == null) {
      fastRemove(index);
      return true;
  }
 } else {
     for (int index = 0; index < size; index++)
  if (o.equals(elementData[index])) {
      fastRemove(index);
      return true;
  }
        }
 return false;
}


private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, 
                             numMoved);
        elementData[--size] = null; // Let gc do its work
}

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

5
задан cka3o4nik 20 April 2010 в 07:54
поделиться

5 ответов

Они не уменьшают базовый массив. Они просто уменьшают размер. Причина в том, что если у вас есть 1000 элементов в массиве и вы удалили 1, зачем перераспределять и копировать массив? Это очень расточительно ради очень небольшой выгоды.

В основном Java ArrayList имеет два важных свойства, и важно понимать, что они разные:

  • размер: сколько элементов условно в Список ; и

  • емкость: сколько элементов может поместиться в базовый массив.

Когда ArrayList расширяется, он увеличивается примерно на 50%, даже если вы добавляете только один элемент. Это аналогичный принцип в обратном порядке. В основном это сводится к следующему: перераспределение массива и копирование значений (относительно) дорого. Настолько, что вы хотите свести это к минимуму. Пока условный размер фабрики равен примерно 2 размерам массива, об этом просто не стоит беспокоиться.

10
ответ дан 18 December 2019 в 11:54
поделиться

Мне нужно еще раз взглянуть на исходный код ArrayList, но remove удаляет объект из массива, а затем, если объект на который не ссылаются никакие другие объекты, сборщик мусора может удалить этот объект. Но размер массива не уменьшается.

1
ответ дан 18 December 2019 в 11:54
поделиться

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

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

0
ответ дан 18 December 2019 в 11:54
поделиться

Насколько мне известно, список ArrayList не сокращается автоматически. Однако вы можете сказать что-то вроде:

ArrayList al = new ArrayList();

// fill the list for demo's sake
for (int i = 0; i < 1000000; ++i)
{
    al.add(i);
}

// now remove all but one element
al.removeRange(1, al.size());

// this should shrink the array back to a decent size
al.trimToSize();

Обратите внимание, объем доступной памяти, вероятно, не изменится, пока GC снова не запустится.

4
ответ дан 18 December 2019 в 11:54
поделиться

Изменение размера внутреннего массива ArrayList не дает большого преимущества, даже если вы используете ArrayList для хранения большого объекта. Список

List<LargeObject> list = new ArrayList<LargetObject>();

будет содержать только ссылку на экземпляр LargeObject, но не сам экземпляр LargeObject.

Ссылка не занимает много места. (Считайте это указателем в C)

0
ответ дан 18 December 2019 в 11:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: