ArrayList的層底是一個Object數組,當執行remove方法的時候,會把對應的元素從後往前移動一位,實現刪除功能,代碼以下:數組
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; // clear to let GC do its work return oldValue; }
但在下面有一句很是關鍵的代碼性能
elementData[--size] = null; // clear to let GC do its work
註釋也說明了,將最後一位元素指定爲null,讓GC來回收,而這一位元素,能夠稱爲過時對象,由於你的size已經執行--操做,你放在數組的最後一位,永遠也不會再被使用,若是你不指定用null來進行回收,隨着垃圾回收器活動的增長,或者因爲不斷的增長內存佔用,程序性能的下降會逐漸的表現出來,在極端的狀況,會出現內存泄露,固然這種狀況確實少見。測試
下面再用一個進棧出棧的小例子來詳細的解釋一個過時對象的引用處理this
public class Stack { private Object[] elements; private int size = 0; public Stack(int capacity) { this.elements = new Object[capacity]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }
這是一段簡單的進棧出棧代碼,在pop()方法中,直接取最後一位元素,同時,記錄數組的size也減了一,這時,一樣如ArrayList同樣,最後一位元素在方法中不再會被引用,成爲過時對象。若是不考慮GC的問題,上段代碼你怎麼測試,都會正常執行,可是咱們不該該讓本身的程序存在這樣一個潛在的GC問題,應在POP方法中,以下解決code
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; return result; }
ArrayList的源碼和上述的例子,都是由於若是不置爲null, 棧內部維護着對這些對象的過時引用(absolete reference)。所謂的過時引用,是指永遠也不會再被解禁的引用。凡是在elements數組的「活動區域(active portion)」以外的引用都是過時的,elements的活動區域是指下標小於size的那一部分。對象
Java內存泄漏是很隱蔽的,若是一個對象引用被無心識地人口負債期起來,那麼GC不只不會處理這個對象,並且也不會處理被這個對象引用的全部其它對象,即便只有少許的幾個對象引用被無心識地保留下來,也會有不少的對象被排除在垃圾回收機制以外,從而對性能形成潛在的重大影響。內存