ArrayList的默认容量为10个对象。当大小超过10个对象时,ArrayList将在内部增加其容量。当我们从ArrayList中删除对象时,容量是否会降低。
如果ArrayList容量没有减少,是否会导致性能问题?
答案 0 :(得分:15)
它不会自动降低这一点。来自文档。
public void trimToSize()
将此ArrayList实例的容量调整为列表的当前大小。应用程序可以使用此操作来最小化ArrayList实例的存储。
答案 1 :(得分:2)
arraylist中有几种删除方法,我将使用remove by index version作为此示例
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = 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;
}
最重要的是要注意,在elementData
内永远不会创建新数组,因此它的大小不会改变,只会复制元素。
如果您需要减少数组列表的容量(通常不会),请使用trimToSize()
答案 2 :(得分:1)
ArrayList提供了一个方法trimToSize() “将此ArrayList实例的容量调整为列表的当前大小。应用程序可以使用此操作来最小化ArrayList实例的存储。”请参阅http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#trimToSize()。
如果任何其他方法默默地执行此类操作,则这取决于JRE提供的实现。
答案 3 :(得分:1)
根据我的理解,只增加了ArrayList的容量,减少它必须将一个数组复制到另一个数组。
我已经尝试过自己的实验来回答你的问题。您无法查找数组列表的当前容量,因此我正在运行垃圾收集器并检查可用内存。
My results are:
Before: 125637904
After Aloc: 126959888 -1321984
After Insert: 126718560 241328
After Clear: 126958496 -239936
After trim: 126998432 -39936
After nullify: 126998400 32
这很奇怪,我无法解释。分配列表减少了可用内存。插入列表增加了可用内存(我没想到)清除列表减少了可用内存(???)修剪列表再次减少可用内存(似乎没有清除它)并将列表指针设置为null应该让我们回到我们开始的地方,但事实并非如此!
我的代码如下:
package metcarob.com.dev.rubbish;
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest {
private static long outputMem(String pre, long last) {
Runtime.getRuntime().gc();
String pre2 = " " + pre;
System.out.print(pre2.substring(pre2.length()-20) + " ");
long tv = Runtime.getRuntime().freeMemory();
System.out.print(tv);
if (last!=0) {
System.out.print(" " + (last - tv));
}
System.out.println("");
return tv;
}
public static void main(String[] args) {
long lm = outputMem("Before:",0);
ArrayList<String> lis = new ArrayList<String>();
lis.ensureCapacity(10000);
lm = outputMem("After Aloc:", lm);
for (int c=0;c<10000;c++) {
lis.add(new String("ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"));
};
lm = outputMem("After Insert:", lm);
lis.clear();
lm = outputMem("After Clear:", lm);
lis.trimToSize();
lm = outputMem("After trim:", lm);
lis = null;
lm = outputMem("After nullify:", lm);
}
}
答案 4 :(得分:1)
您询问了性能影响。你必须通过“降低”表现来澄清你的意思。如果每次减少数组时都必须调整数组大小,那么每次都会重新复制数组。另一方面,如果容量保持不变,那么你就占用了不必要的内存。
这是您的用例,它决定了它如何影响用户感知的性能。它们是在内存不足的机器上运行吗?我们在讨论大型静态数组吗?阵列是否一直在变化?
Java实现仅在需要时才更改底层数组。这有利于以内存大小为代价避免不必要的拷贝。但是,如果有必要,它们可以让你修剪它。
答案 5 :(得分:1)
当我们删除元素时,ArrayList
的容量是否会减少?
没有。这是一个实现细节,但是 ArrayList
类的 AFAIK 没有(标准)实现会在删除元素时自动减少列表的容量。
如果 ArrayList
容量没有减少,是否会导致性能问题?
嗯,一般不会。
首先,列表通常不会缩小。 (大多数列表的生命周期相对较短。它们是通过附加进行处理、构建然后进行处理的。列表元素的删除相对不常见……尽管这取决于应用程序。)因此,大多数情况下,这个问题没有实际意义。>
其次,除非 ArrayList
严重过大,否则列表末尾以外的未使用空间不会显着影响性能。事实上,任何东西受到直接影响的唯一时间是列表被垃圾收集器标记和复制的时候。并且影响相对较小,因为超出 ArrayList
逻辑端的区域总是被清除为 null
以防止内存泄漏。
值得注意的是,通过附加到初始空列表来创建的 ArrayList
可能有一个平均大 50% 的后备数组。这是因为 ArrayList
扩展后备数组的内置策略是将其大小加倍。这使 append
成为摊销的 O(1)
操作。
第三,delete
或类似操作不“知道”列表接下来会发生什么,因此无法判断调整大小是否合适。
如果您的应用确实需要,它可以在删除元素后调用 trimToSize()
。但是,请注意:
调用 trimToSize()
的开销很大。 ArrayList
实现将创建一个全新的支持数组(大小正好合适)并复制所有数组元素。
下次在 ArrayList
之后插入或追加元素到 trimToSize()
时,操作将被迫重新分配后备数组......再次。新容量将是当前列表大小的两倍。
事实上,如果您考虑在每次删除后自动缩小 ArrayList
几乎可以保证性能不佳,因为重新分配和复制会触发。
插入和删除的成本将比目前高得多,对于某些使用模式,append
平均会变成 O(N)
。
答案 6 :(得分:0)
do the the capacity decrease when we remove the object from ArrayList.
答案只是否。如果您观察ArrayList课程的源代码,您将得到答案。
没有降低ArrayList remove()
方法容量的操作。