ArrayList 源码分析扩容过程及性能优化
ArrayList 默认初始化过程,初始容量为10的空列表
//首先我们看源码,无参构造函数 /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的初始化 /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //可以再看一下add方法中,调用的ensureCapacityInternal方法中判断elementData == EMPTY_ELEMENTDATA 是否为空,如果为空,minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);,minCapacity设置为其中的大值,在默认是空的时候,初次调用add方法传入的参数是1,也就是这里的minCapacity就是1,现在minCapcity变成了DEFAULT_CAPACITY 也就是10 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } //默认值 /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10;
ArrayList的扩容规律
通过下面的源码发现,如果空间不够,会通过Arrays.copyOf()创建一个新的内存空间,新空间的大小最小为原空间的1.5倍,这里是通过位移运算,效果相当于 oldCapacity/2 = oldCapacity >> 1
/** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
通过以上源码可以看到,ArrayList是非常浪费内存的,当集合太大的时候,很容易出现OOM 那么在知道List长度范围的情况下,在实例化ArrayList的时候带上长度 new ArrayList(256),来 降低内存碎片和内存拷贝次数。 当文本内容或者Excel大量导入场景时,可以考虑先做分段处理,而不是一次导入到内存中
Vector
vector 初始化大小也是10,与ArrayList 不同的是动态策略不同,和加有synchronized关键字确定方法临界区,使线程同步
public Vector() { this(10); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }public synchronized void setSize(int newSize) { modCount++; if (newSize > elementCount) { ensureCapacityHelper(newSize); } else { for (int i = newSize ; i < elementCount ; i++) { elementData[i] = null; } } elementCount = newSize; }
LinkedList
LinkedList 的数据结构为双向链表,双向链表与数组的优点为,遍历 删除 元素 都优与动态数组的ArrayList