消除过期对象的引用
在Java编码的过程中,只要类是自己管理内存的,就要警惕对象的回收,防止出现
内存泄漏的问题。
对象的过期引用,是指在不再会使用到引用永远也不会也不会再被解除引用。
举个例子说明下:
public class Stack<T> {
private Object[] mElements;
private int mSize;
private static final int DEFAULT_SIZE = 16;
public Stack() {
mElements = new Object[DEFAULT_SIZE];
}
public void push(T e) {
checkCapacity();
mElements[mSize++] = e;
}
private void checkCapacity() {
if (mElements.length == mSize) {
//数组已满,需要扩容
mElements = Arrays.copyOf(mElements, 2 * mSize + 1);
}
}
public T pop() throws Exception {
if (mSize == 0) {
throw new Exception("stack is null");
}
return (T) mElements[mSize--];
}
}
上面的代码模拟的是一个栈操作的类,主要是提供了入栈(push)和出栈(pop)的操作,
如果不细心看的话可能不容易发现这段代码存在什么样的问题,在程序中使用或编写测试用例可能
出现问题的可能性也很低,但仍然不可否认这是一段有问题否认代码。大量的对象入栈出栈操作后,内存会逐渐升高,性能降低,甚至是出现内存泄漏。
问题出在哪呢?
public T pop() throws Exception {
if (mSize == 0) {
throw new Exception("stack is null");
}
return (T) mElements[mSize--];
}
问题就出在出栈操作里,当返回栈顶的元素时,Stack的大小已经收缩(size-1),
但此时Stack内维护的数组mElements的实际大小是大于mSize的,数组在index大于mSize
后面的元素还持有了外部对象的引用,导致垃圾回收器不会去回收那些过期的对象(Stack在
出栈操作后,size收缩,意味数组size后面的元素不会再被使用,属于过期的对象),因此不断的
加入对象和弹出对象后会导致内存增加,直到内存泄漏。
如何改善此处代码呢?
因为在此Stack类里面是自己管理内存的,所以在元素出栈的时候需要取消对该对象的引用,
利于垃圾回收器将其回收。修改后的代码如下:
public T pop() throws Exception {
if (mSize == 0) {
throw new Exception("stack is null");
}
Object result = mElements[mSize--];
mElements[mSize] = null;
return (T) result;
}
/*
修改:在出栈后,数组末尾的对象属于过期对象,需要垃圾回收器及时回收,
所以在出栈后,将数组末尾的元素引用置空
*/