Java:ArrayList如何管理内存

时间:2010-04-20 07:40:35

标签: java memory arraylist

在我的Data Structures类中,我们研究了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 个答案:

答案 0 :(得分:10)

它们不会减少底层数组。它们只是减小了尺寸。这样做的原因是,如果数组中有1000个元素并删除1,为什么要重新分配和复制数组?很少收获,这是非常浪费的。

基本上Java ArrayList有两个重要的属性,重要的是要理解它们是不同的:

  • 尺寸: List名义的元素数量;以及

  • 容量 可以在基础数组中适合的元素数量。

ArrayList扩展时,即使您只添加一个元素,它的大小也会增加约50%。这是一个相反的原理。基本上它归结为:重新分配数组并复制值(相对)昂贵。这么多,以至于你想尽量减少它的发生。只要名义尺寸的阵列大小约为2的工厂,就不值得担心。

答案 1 :(得分:4)

据我所知,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再次运行。

答案 2 :(得分:1)

我必须再看看ArrayList的源代码,但是remove从数组中删除了对象,然后如果该对象没有被任何其他对象引用,则GC可以删除该对象。但阵列大小并没有减少。

答案 3 :(得分:0)

通过调整ArrayList内部数组的大小没有太大的收获,即使您使用ArrayList来保存大对象。

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

list只保存对LargeObject实例的引用,而不保存LargeObject实例本身。

参考不会占用太多空间。 (把它想象成C中的指针)

答案 4 :(得分:0)

数组大小永远不会自动减少。实际上有一个列表首先填充了大量的元素,然后将其清空但仍然保持不变,这是非常罕见的。并且请记住,必须有足够的内存来保存列表(仅包含引用)及其元素 - 然后空列表消耗的内存不太可能是一个问题。

如果你真的遇到一个奇怪的算法,这会成为一个问题,你仍然可以通过手动调用trimToSize()来释放内存。