Java:ArrayList 如何管理内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2673398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: How ArrayList manages memory
提问by cka3o4nik
In my Data Structures class we have studies the Java ArrayList class, and how it grows the underlying array when a user adds more elements. That is understood. However, I cannot figure out how exactly this class frees up memory when lots of elements are removed from the list. Looking at the source, there are three methods that remove elements:
在我的数据结构类中,我们研究了 Java ArrayList 类,以及当用户添加更多元素时它如何增长底层数组。这是明白的。但是,当从列表中删除大量元素时,我无法弄清楚这个类究竟是如何释放内存的。查看源码,删除元素的方法有3种:
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
}
None of them reduce the datastore array. I even started questioning if memory free up ever happens, but empirical tests show that it does. So there must be some other way it is done, but where and how? I checked the parent classes as well with no success.
它们都没有减少数据存储阵列。我什至开始质疑内存释放是否曾经发生过,但经验测试表明确实如此。所以一定有其他方法可以完成,但在哪里以及如何完成?我也检查了父类,但没有成功。
回答by cletus
They don't reduce the underlying array. They simply decrement the size. The reasoning for this is that if you have 1000 elements in an array and delete 1, why reallocate and copy the array? It's hugely wasteful for very little gain.
它们不会减少底层数组。他们只是减少大小。这样做的原因是,如果数组中有 1000 个元素并删除 1,为什么要重新分配和复制数组?对于很少的收益,这是非常浪费的。
Basically Java ArrayLists have two important properties and it's important to understand they are different:
基本上 JavaArrayList有两个重要的属性,理解它们的不同很重要:
size:how many elements are notionallyin the
List; andcapacity:how many elements canfit in the underlying array.
大小:有多少元素的名义上的
List; 和容量:底层数组中可以容纳多少元素。
When an ArrayListexpands, it grows by about 50% in size even if you're only adding one element. This is a similar principle in reverse. Basically it comes down to this: reallocating the array and copying the values is (relatively) expensive. So much so that you want to minimize it happening. As long as the notional size is with a factory of about 2 of the array size, it's just not worth worrying about.
当一个ArrayList扩展时,即使您只添加一个元素,它的大小也会增长约 50%。这是一个类似的反向原理。基本上归结为:重新分配数组并复制值是(相对)昂贵的。如此之多以至于你想尽量减少它的发生。只要名义大小是数组大小的大约 2 的工厂,就不值得担心。
回答by cHao
An ArrayList doesn't automatically shrink back, as far as i know. However, you can say something like:
据我所知,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();
Note, the amount of memory available probably won't change til the GC runs again.
请注意,在 GC 再次运行之前,可用内存量可能不会改变。
回答by Behrang Saeedzadeh
I have to have another look at ArrayList's source code, but removeremoves the object from the array, and then if the object is not referenced to by any other objects, the GC can delete that object. But the array size is not decreased.
我必须再看看ArrayList的源代码,但是remove从数组中删除对象,然后如果该对象没有被任何其他对象引用,GC可以删除该对象。但数组大小并没有减少。
回答by Cheok Yan Cheng
There is not much gain by resizing the ArrayList internal array, even you are using ArrayList to hold a large object.
调整 ArrayList 内部数组的大小并没有太大的好处,即使您使用 ArrayList 来保存一个大对象。
List<LargeObject> list = new ArrayList<LargetObject>();
list will only hold reference to LargeObject instance, and not holding LargeObject instance itself.
list 将只保存对 LargeObject 实例的引用,而不保存 LargeObject 实例本身。
Reference doesn't consume much space. (Think it as pointer in C)
引用不占用太多空间。(将其视为 C 中的指针)
回答by Michael Borgwardt
The array size is never reduced automatically. It's very rare to actually have a list that is first filled with a large number of elements, then have it emptied but still kept around. And keep in mind that there must have been enough memory to hold the list (which consists only of references) and its elements - unlikely then that the memory consumed by the empty list would be a problem.
数组大小永远不会自动减少。实际上很少有列表首先填充大量元素,然后将其清空但仍然保留。并且请记住,必须有足够的内存来保存列表(仅由引用组成)及其元素 - 那么空列表消耗的内存不太可能成为问题。
If you really encounter an algorithm bizarre enough that this becomes a problem, you can still free the memory by calling trimToSize()manually.
如果你真的遇到一个足够奇怪的算法,这会成为一个问题,你仍然可以通过trimToSize()手动调用来释放内存。

