你能看出以下代碼哪里內(nèi)存泄漏嗎堪嫂?
// Can you spot the "memory leak"?
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
答案是:
pop()方法存在內(nèi)存泄漏藻肄。
內(nèi)存泄漏可以稱為“ 無意識的對象保持(unintentional object retention)”。
在pop()方法中從棧中彈出來的對象將不會被當(dāng)做垃圾回收间学。棧內(nèi)部維護著對這些對象的過期引用(obsolete reference)殷费。所謂的過期引用,是指永遠(yuǎn)也不會再被解除的引用低葫。凡是在elements數(shù)組的“活動部分”(active portion)之外的任何引用都是過期的详羡。活動部分是指elements中下標(biāo)小于size的那些元素氮采。
解決方法:上述述例子中的Stack類而言殷绍,只要一個單元被彈出棧,指向它的引用就過期了鹊漠。一旦數(shù)組元素變成了非活動部分的一部分主到,就手工清空這些數(shù)組元素。修改后的pop()方法如下:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];//result相當(dāng)于一個temp躯概。
elements[size] = null; // Eliminate obsolete reference
return result;
}
清空對象引用應(yīng)該是一種例外登钥,而不是一種規(guī)范行為。消除過期引用最好的方法是讓包含該引用的變量結(jié)束其生命周期娶靡。
延伸閱讀
length牧牢、size()、length()的區(qū)別:
- 數(shù)組的長度(length):數(shù)組能容納元素個數(shù)的值
- 泛型集合的大凶硕А(size()):泛型中元素的個數(shù)
- 字符串的長度(length()):字符的個數(shù)
前綴遞減和后綴遞增:
- 前綴遞減塔鳍,"--"操作符位于變量或表達式前,先執(zhí)行運算呻此,再生成值轮纫。如上例中
elements[--size]
,size大小先減1,所以Object result = elements[--size];
中result元素下標(biāo)為size=size-1焚鲜。 - 后綴遞增掌唾,"++"操作符位于變量或表達式后,先生成值忿磅,再執(zhí)行運算糯彬。如上例中
elements[size++] = e;
,元素下標(biāo)為size葱她,再執(zhí)行運算size=size+1撩扒。
Arrays.copyOf()方法:
- a copy of the original array, truncated or padded with nulls to obtain the specified length(原始數(shù)組的副本,縮短或填補null來獲取指定的長度)。
- 作用:如果數(shù)組元素的個數(shù)等于數(shù)組的長度吨些,新建副本數(shù)組搓谆,將長度擴大為兩倍加一,將數(shù)組副本賦值給elements锤灿。